initial commit

This commit is contained in:
Jörg Prante 2016-01-07 19:22:16 +01:00
commit 0bb5cf504b
258 changed files with 39412 additions and 0 deletions

12
.gitignore vendored Normal file
View file

@ -0,0 +1,12 @@
/data
/work
/logs
/.idea
/target
.DS_Store
*.iml
/.settings
/.classpath
/.project
/.gradle
/build

7
.travis.yml Normal file
View file

@ -0,0 +1,7 @@
sudo: false
language: java
jdk:
- oraclejdk8
cache:
directories:
- $HOME/.m2

202
LICENSE.txt Normal file
View file

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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.

32
README.md Normal file
View file

@ -0,0 +1,32 @@
= Guice
This is a xbib Guice, a build of Guice with the following differences to the
original [Google Guice Core Library](https://github.com/google/guice):
- only external dependencies are
-- javax.inject:javax.inject:1
-- javax.annotation:javax.annotation-api:1.2
-- com.google.guava:guava:19.0
- the extra AOP stuff was removed (aopalliance/cglib), no intercepting any more
- removed all logging, uses of java.util.logger.* stuff and logger default binding
- removed all java.io.Serializable dependent stuff
- reformatted source by IntelliJ and cleaned up source of @author and @since tags
- target of compilation is Java 8, no support for Java 6/7
- introduced Gradle as build system
- junit tests made compatible to junit 4.12
All credits belong to the original authors, especially Bob Lee http://blog.crazybob.org/
= License
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.

90
build.gradle Normal file
View file

@ -0,0 +1,90 @@
def xbibGroup = 'org.xbib'
def xbibVersion = '4.0'
group = xbibGroup
version = xbibVersion
println "Current JVM: " + org.gradle.internal.jvm.Jvm.current()
apply plugin: 'java'
apply plugin: 'maven'
repositories {
mavenCentral()
mavenLocal()
jcenter()
maven {
url "http://xbib.org/repository"
}
}
configurations {
wagon
}
dependencies {
compile "javax.inject:javax.inject:1"
compile 'javax.annotation:javax.annotation-api:1.2'
compile "com.google.guava:guava:19.0"
testCompile "junit:junit:4.12"
testCompile "org.apache.logging.log4j:log4j-slf4j-impl:2.5"
testCompile "org.apache.logging.log4j:log4j-core:2.5"
testCompile "javax.inject:javax.inject-tck:1"
testCompile "com.google.guava:guava-testlib:19.0"
wagon 'org.apache.maven.wagon:wagon-ssh-external:2.10'
}
sourceCompatibility = 1.8
targetCompatibility = 1.8
[compileJava, compileTestJava]*.options.collect { options ->
options.encoding = 'UTF-8'
options.compilerArgs << '-Xlint:-serial,-path,-rawtypes,-unchecked'
}
test {
exclude '*$*'
exclude '**/ErrorHandlingTest*'
exclude '**/OSGiContainerTest*'
exclude '**/ScopesTest*'
exclude '**/TypeConversionTest*'
testLogging {
showStandardStreams = false
exceptionFormat = 'full'
}
}
task sourcesJar(type: Jar, dependsOn: classes) {
from sourceSets.main.allSource
classifier 'sources'
}
artifacts {
archives sourcesJar
}
uploadArchives {
repositories {
if (project.hasProperty("xbibUsername")) {
mavenDeployer {
configuration = configurations.wagon
repository(
id: 'xbib.org',
url: uri('scpexe://xbib.org/repository'),
authentication: [userName: xbibUsername, privateKey: xbibPrivateKey]
)
pom.project {
inceptionYear '2016'
licenses {
license {
name 'The Apache Software License, Version 2.0'
url 'http://www.apache.org/licenses/LICENSE-2.0.txt'
distribution 'repo'
}
}
}
}
}
}
}

100
pom.xml Normal file
View file

@ -0,0 +1,100 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.xbib</groupId>
<artifactId>guice</artifactId>
<version>4.0</version>
<name>Guice</name>
<dependencies>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
<dependency>
<groupId>javax.annotation</groupId>
<artifactId>javax.annotation-api</artifactId>
<version>1.2</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>19.0</version>
</dependency>
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject-tck</artifactId>
<version>1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava-testlib</artifactId>
<version>19.0</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.3</version>
<configuration>
<encoding>UTF-8</encoding>
<source>1.8</source>
<target>1.8</target>
<optimize>true</optimize>
<debug>true</debug>
<showDeprecation>true</showDeprecation>
<showWarnings>true</showWarnings>
<compilerArgument>-Xlint:all,-serial,-path,-rawtypes,-unchecked</compilerArgument>
</configuration>
</plugin>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.19.1</version>
<configuration>
<excludes>
<exclude>**/*$*</exclude>
<exclude>**/ErrorHandlingTest*</exclude>
<exclude>**/OSGiContainerTest*</exclude>
<exclude>**/ScopesTest*</exclude>
<exclude>**/TypeConversionTest*</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<configuration>
<excludes>
<exclude>LICENSE</exclude>
<exclude>NOTICE</exclude>
</excludes>
</configuration>
</plugin>
<plugin>
<artifactId>maven-source-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.10.3</version>
</plugin>
</plugins>
</build>
</project>

1
settings.gradle Normal file
View file

@ -0,0 +1 @@
rootProject.name = 'guice'

View file

@ -0,0 +1,220 @@
package com.google.inject;
import com.google.inject.binder.AnnotatedBindingBuilder;
import com.google.inject.binder.AnnotatedConstantBindingBuilder;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.matcher.Matcher;
import com.google.inject.spi.Message;
import com.google.inject.spi.ProvisionListener;
import com.google.inject.spi.TypeConverter;
import com.google.inject.spi.TypeListener;
import java.lang.annotation.Annotation;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
/**
* A support class for {@link Module}s which reduces repetition and results in
* a more readable configuration. Simply extend this class, implement {@link
* #configure()}, and call the inherited methods which mirror those found in
* {@link Binder}. For example:
*
* <pre>
* public class MyModule extends AbstractModule {
* protected void configure() {
* bind(Service.class).to(ServiceImpl.class).in(Singleton.class);
* bind(CreditCardPaymentService.class);
* bind(PaymentService.class).to(CreditCardPaymentService.class);
* bindConstant().annotatedWith(Names.named("port")).to(8080);
* }
* }
* </pre>
*
*/
public abstract class AbstractModule implements Module {
Binder binder;
public final synchronized void configure(Binder builder) {
checkState(this.binder == null, "Re-entry is not allowed.");
this.binder = checkNotNull(builder, "builder");
try {
configure();
} finally {
this.binder = null;
}
}
/**
* Configures a {@link Binder} via the exposed methods.
*/
protected abstract void configure();
/**
* Gets direct access to the underlying {@code Binder}.
*/
protected Binder binder() {
checkState(binder != null, "The binder can only be used inside configure()");
return binder;
}
/**
* @see Binder#bindScope(Class, Scope)
*/
protected void bindScope(Class<? extends Annotation> scopeAnnotation,
Scope scope) {
binder().bindScope(scopeAnnotation, scope);
}
/**
* @see Binder#bind(Key)
*/
protected <T> LinkedBindingBuilder<T> bind(Key<T> key) {
return binder().bind(key);
}
/**
* @see Binder#bind(TypeLiteral)
*/
protected <T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral) {
return binder().bind(typeLiteral);
}
/**
* @see Binder#bind(Class)
*/
protected <T> AnnotatedBindingBuilder<T> bind(Class<T> clazz) {
return binder().bind(clazz);
}
/**
* @see Binder#bindConstant()
*/
protected AnnotatedConstantBindingBuilder bindConstant() {
return binder().bindConstant();
}
/**
* @see Binder#install(Module)
*/
protected void install(Module module) {
binder().install(module);
}
/**
* @see Binder#addError(String, Object[])
*/
protected void addError(String message, Object... arguments) {
binder().addError(message, arguments);
}
/**
* @see Binder#addError(Throwable)
*/
protected void addError(Throwable t) {
binder().addError(t);
}
/**
* @see Binder#addError(Message)
*/
protected void addError(Message message) {
binder().addError(message);
}
/**
* @see Binder#requestInjection(Object)
*/
protected void requestInjection(Object instance) {
binder().requestInjection(instance);
}
/**
* @see Binder#requestStaticInjection(Class[])
*/
protected void requestStaticInjection(Class<?>... types) {
binder().requestStaticInjection(types);
}
/**
* Adds a dependency from this module to {@code key}. When the injector is
* created, Guice will report an error if {@code key} cannot be injected.
* Note that this requirement may be satisfied by implicit binding, such as
* a public no-arguments constructor.
*/
protected void requireBinding(Key<?> key) {
binder().getProvider(key);
}
/**
* Adds a dependency from this module to {@code type}. When the injector is
* created, Guice will report an error if {@code type} cannot be injected.
* Note that this requirement may be satisfied by implicit binding, such as
* a public no-arguments constructor.
*/
protected void requireBinding(Class<?> type) {
binder().getProvider(type);
}
/**
* @see Binder#getProvider(Key)
*/
protected <T> Provider<T> getProvider(Key<T> key) {
return binder().getProvider(key);
}
/**
* @see Binder#getProvider(Class)
*/
protected <T> Provider<T> getProvider(Class<T> type) {
return binder().getProvider(type);
}
/**
* @see Binder#convertToTypes
*/
protected void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher,
TypeConverter converter) {
binder().convertToTypes(typeMatcher, converter);
}
/**
* @see Binder#currentStage()
*/
protected Stage currentStage() {
return binder().currentStage();
}
/**
* @see Binder#getMembersInjector(Class)
*/
protected <T> MembersInjector<T> getMembersInjector(Class<T> type) {
return binder().getMembersInjector(type);
}
/**
* @see Binder#getMembersInjector(TypeLiteral)
*/
protected <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> type) {
return binder().getMembersInjector(type);
}
/**
* @see Binder#bindListener(com.google.inject.matcher.Matcher,
* com.google.inject.spi.TypeListener)
*/
protected void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher,
TypeListener listener) {
binder().bindListener(typeMatcher, listener);
}
/**
* @see Binder#bindListener(Matcher, ProvisionListener...)
*/
protected void bindListener(Matcher<? super Binding<?>> bindingMatcher,
ProvisionListener... listener) {
binder().bindListener(bindingMatcher, listener);
}
}

View file

@ -0,0 +1,451 @@
package com.google.inject;
import com.google.inject.binder.AnnotatedBindingBuilder;
import com.google.inject.binder.AnnotatedConstantBindingBuilder;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.matcher.Matcher;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.Message;
import com.google.inject.spi.ModuleAnnotatedMethodScanner;
import com.google.inject.spi.ProvisionListener;
import com.google.inject.spi.TypeConverter;
import com.google.inject.spi.TypeListener;
import java.lang.annotation.Annotation;
import java.lang.reflect.Proxy;
/**
* Collects configuration information (primarily <i>bindings</i>) which will be
* used to create an {@link Injector}. Guice provides this object to your
* application's {@link Module} implementors so they may each contribute
* their own bindings and other registrations.
*
* <h3>The Guice Binding EDSL</h3>
*
* Guice uses an <i>embedded domain-specific language</i>, or EDSL, to help you
* create bindings simply and readably. This approach is great for overall
* usability, but it does come with a small cost: <b>it is difficult to
* learn how to use the Binding EDSL by reading
* method-level javadocs</b>. Instead, you should consult the series of
* examples below. To save space, these examples omit the opening
* {@code binder}, just as you will if your module extends
* {@link AbstractModule}.
*
* <pre>
* bind(ServiceImpl.class);</pre>
*
* This statement does essentially nothing; it "binds the {@code ServiceImpl}
* class to itself" and does not change Guice's default behavior. You may still
* want to use this if you prefer your {@link Module} class to serve as an
* explicit <i>manifest</i> for the services it provides. Also, in rare cases,
* Guice may be unable to validate a binding at injector creation time unless it
* is given explicitly.
*
* <pre>
* bind(Service.class).to(ServiceImpl.class);</pre>
*
* Specifies that a request for a {@code Service} instance with no binding
* annotations should be treated as if it were a request for a
* {@code ServiceImpl} instance. This <i>overrides</i> the function of any
* {@link ImplementedBy @ImplementedBy} or {@link ProvidedBy @ProvidedBy}
* annotations found on {@code Service}, since Guice will have already
* "moved on" to {@code ServiceImpl} before it reaches the point when it starts
* looking for these annotations.
*
* <pre>
* bind(Service.class).toProvider(ServiceProvider.class);</pre>
*
* In this example, {@code ServiceProvider} must extend or implement
* {@code Provider<Service>}. This binding specifies that Guice should resolve
* an unannotated injection request for {@code Service} by first resolving an
* instance of {@code ServiceProvider} in the regular way, then calling
* {@link Provider#get get()} on the resulting Provider instance to obtain the
* {@code Service} instance.
*
* <p>The {@link Provider} you use here does not have to be a "factory"; that
* is, a provider which always <i>creates</i> each instance it provides.
* However, this is generally a good practice to follow. You can then use
* Guice's concept of {@link Scope scopes} to guide when creation should happen
* -- "letting Guice work for you".
*
* <pre>
* bind(Service.class).annotatedWith(Red.class).to(ServiceImpl.class);</pre>
*
* Like the previous example, but only applies to injection requests that use
* the binding annotation {@code @Red}. If your module also includes bindings
* for particular <i>values</i> of the {@code @Red} annotation (see below),
* then this binding will serve as a "catch-all" for any values of {@code @Red}
* that have no exact match in the bindings.
*
* <pre>
* bind(ServiceImpl.class).in(Singleton.class);
* // or, alternatively
* bind(ServiceImpl.class).in(Scopes.SINGLETON);</pre>
*
* Either of these statements places the {@code ServiceImpl} class into
* singleton scope. Guice will create only one instance of {@code ServiceImpl}
* and will reuse it for all injection requests of this type. Note that it is
* still possible to bind another instance of {@code ServiceImpl} if the second
* binding is qualified by an annotation as in the previous example. Guice is
* not overly concerned with <i>preventing</i> you from creating multiple
* instances of your "singletons", only with <i>enabling</i> your application to
* share only one instance if that's all you tell Guice you need.
*
* <p><b>Note:</b> a scope specified in this way <i>overrides</i> any scope that
* was specified with an annotation on the {@code ServiceImpl} class.
*
* <p>Besides {@link Singleton}/{@link Scopes#SINGLETON}, there are
* servlet-specific scopes available in
* {@code com.google.inject.servlet.ServletScopes}, and your Modules can
* contribute their own custom scopes for use here as well.
*
* <pre>
* bind(new TypeLiteral&lt;PaymentService&lt;CreditCard>>() {})
* .to(CreditCardPaymentService.class);</pre>
*
* This admittedly odd construct is the way to bind a parameterized type. It
* tells Guice how to honor an injection request for an element of type
* {@code PaymentService<CreditCard>}. The class
* {@code CreditCardPaymentService} must implement the
* {@code PaymentService<CreditCard>} interface. Guice cannot currently bind or
* inject a generic type, such as {@code Set<E>}; all type parameters must be
* fully specified.
*
* <pre>
* bind(Service.class).toInstance(new ServiceImpl());
* // or, alternatively
* bind(Service.class).toInstance(SomeLegacyRegistry.getService());</pre>
*
* In this example, your module itself, <i>not Guice</i>, takes responsibility
* for obtaining a {@code ServiceImpl} instance, then asks Guice to always use
* this single instance to fulfill all {@code Service} injection requests. When
* the {@link Injector} is created, it will automatically perform field
* and method injection for this instance, but any injectable constructor on
* {@code ServiceImpl} is simply ignored. Note that using this approach results
* in "eager loading" behavior that you can't control.
*
* <pre>
* bindConstant().annotatedWith(ServerHost.class).to(args[0]);</pre>
*
* Sets up a constant binding. Constant injections must always be annotated.
* When a constant binding's value is a string, it is eligile for conversion to
* all primitive types, to {@link Enum#valueOf(Class, String) all enums}, and to
* {@link Class#forName class literals}. Conversions for other types can be
* configured using {@link #convertToTypes(Matcher, TypeConverter)
* convertToTypes()}.
*
* <pre>
* {@literal @}Color("red") Color red; // A member variable (field)
* . . .
* red = MyModule.class.getDeclaredField("red").getAnnotation(Color.class);
* bind(Service.class).annotatedWith(red).to(RedService.class);</pre>
*
* If your binding annotation has parameters you can apply different bindings to
* different specific values of your annotation. Getting your hands on the
* right instance of the annotation is a bit of a pain -- one approach, shown
* above, is to apply a prototype annotation to a field in your module class, so
* that you can read this annotation instance and give it to Guice.
*
* <pre>
* bind(Service.class)
* .annotatedWith(Names.named("blue"))
* .to(BlueService.class);</pre>
*
* Differentiating by names is a common enough use case that we provided a
* standard annotation, {@link com.google.inject.name.Named @Named}. Because of
* Guice's library support, binding by name is quite easier than in the
* arbitrary binding annotation case we just saw. However, remember that these
* names will live in a single flat namespace with all the other names used in
* your application.
*
* <pre>
* Constructor<T> loneCtor = getLoneCtorFromServiceImplViaReflection();
* bind(ServiceImpl.class)
* .toConstructor(loneCtor);</pre>
*
* In this example, we directly tell Guice which constructor to use in a concrete
* class implementation. It means that we do not need to place {@literal @}Inject
* on any of the constructors and that Guice treats the provided constructor as though
* it were annotated so. It is useful for cases where you cannot modify existing
* classes and is a bit simpler than using a {@link Provider}.
*
* <p>The above list of examples is far from exhaustive. If you can think of
* how the concepts of one example might coexist with the concepts from another,
* you can most likely weave the two together. If the two concepts make no
* sense with each other, you most likely won't be able to do it. In a few
* cases Guice will let something bogus slip by, and will then inform you of
* the problems at runtime, as soon as you try to create your Injector.
*
* <p>The other methods of Binder such as {@link #bindScope},
* {@link #install}, {@link #requestStaticInjection},
* {@link #addError} and {@link #currentStage} are not part of the Binding EDSL;
* you can learn how to use these in the usual way, from the method
* documentation.
*/
public interface Binder {
/**
* Binds a scope to an annotation.
*/
void bindScope(Class<? extends Annotation> annotationType, Scope scope);
/**
* See the EDSL examples at {@link Binder}.
*/
<T> LinkedBindingBuilder<T> bind(Key<T> key);
/**
* See the EDSL examples at {@link Binder}.
*/
<T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral);
/**
* See the EDSL examples at {@link Binder}.
*/
<T> AnnotatedBindingBuilder<T> bind(Class<T> type);
/**
* See the EDSL examples at {@link Binder}.
*/
AnnotatedConstantBindingBuilder bindConstant();
/**
* Upon successful creation, the {@link Injector} will inject instance fields
* and methods of the given object.
*
* @param type of instance
* @param instance for which members will be injected
*/
<T> void requestInjection(TypeLiteral<T> type, T instance);
/**
* Upon successful creation, the {@link Injector} will inject instance fields
* and methods of the given object.
*
* @param instance for which members will be injected
*/
void requestInjection(Object instance);
/**
* Upon successful creation, the {@link Injector} will inject static fields
* and methods in the given classes.
*
* @param types for which static members will be injected
*/
void requestStaticInjection(Class<?>... types);
/**
* Uses the given module to configure more bindings.
*/
void install(Module module);
/**
* Gets the current stage.
*/
Stage currentStage();
/**
* Records an error message which will be presented to the user at a later
* time. Unlike throwing an exception, this enable us to continue
* configuring the Injector and discover more errors. Uses {@link
* String#format(String, Object[])} to insert the arguments into the
* message.
*/
void addError(String message, Object... arguments);
/**
* Records an exception, the full details of which will be logged, and the
* message of which will be presented to the user at a later
* time. If your Module calls something that you worry may fail, you should
* catch the exception and pass it into this.
*/
void addError(Throwable t);
/**
* Records an error message to be presented to the user at a later time.
*/
void addError(Message message);
/**
* Returns the provider used to obtain instances for the given injection key.
* The returned provider will not be valid until the {@link Injector} has been
* created. The provider will throw an {@code IllegalStateException} if you
* try to use it beforehand.
*
*/
<T> Provider<T> getProvider(Key<T> key);
/**
* Returns the provider used to obtain instances for the given injection key.
* The returned provider will be attached to the injection point and will
* follow the nullability specified in the dependency.
* Additionally, the returned provider will not be valid until the {@link Injector}
* has been created. The provider will throw an {@code IllegalStateException} if you
* try to use it beforehand.
*/
<T> Provider<T> getProvider(Dependency<T> dependency);
/**
* Returns the provider used to obtain instances for the given injection type.
* The returned provider will not be valid until the {@link Injector} has been
* created. The provider will throw an {@code IllegalStateException} if you
* try to use it beforehand.
*/
<T> Provider<T> getProvider(Class<T> type);
/**
* Returns the members injector used to inject dependencies into methods and fields on instances
* of the given type {@code T}. The returned members injector will not be valid until the main
* {@link Injector} has been created. The members injector will throw an {@code
* IllegalStateException} if you try to use it beforehand.
*
* @param typeLiteral type to get members injector for
*/
<T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral);
/**
* Returns the members injector used to inject dependencies into methods and fields on instances
* of the given type {@code T}. The returned members injector will not be valid until the main
* {@link Injector} has been created. The members injector will throw an {@code
* IllegalStateException} if you try to use it beforehand.
*
* @param type type to get members injector for
*/
<T> MembersInjector<T> getMembersInjector(Class<T> type);
/**
* Binds a type converter. The injector will use the given converter to
* convert string constants to matching types as needed.
*
* @param typeMatcher matches types the converter can handle
* @param converter converts values
*/
void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher,
TypeConverter converter);
/**
* Registers a listener for injectable types. Guice will notify the listener when it encounters
* injectable types matched by the given type matcher.
*
* @param typeMatcher that matches injectable types the listener should be notified of
* @param listener for injectable types matched by typeMatcher
*/
void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher,
TypeListener listener);
/**
* Registers listeners for provisioned objects. Guice will notify the
* listeners just before and after the object is provisioned. Provisioned
* objects that are also injectable (everything except objects provided
* through Providers) can also be notified through TypeListeners registered in
* {@link #bindListener}.
*
* @param bindingMatcher that matches bindings of provisioned objects the listener
* should be notified of
* @param listeners for provisioned objects matched by bindingMatcher
*/
void bindListener(Matcher<? super Binding<?>> bindingMatcher, ProvisionListener... listeners);
/**
* Returns a binder that uses {@code source} as the reference location for
* configuration errors. This is typically a {@link StackTraceElement}
* for {@code .java} source but it could any binding source, such as the
* path to a {@code .properties} file.
*
* @param source any object representing the source location and has a
* concise {@link Object#toString() toString()} value
* @return a binder that shares its configuration with this binder
*/
Binder withSource(Object source);
/**
* Returns a binder that skips {@code classesToSkip} when identify the
* calling code. The caller's {@link StackTraceElement} is used to locate
* the source of configuration errors.
*
* @param classesToSkip library classes that create bindings on behalf of
* their clients.
* @return a binder that shares its configuration with this binder.
*/
Binder skipSources(Class... classesToSkip);
/**
* Creates a new private child environment for bindings and other configuration. The returned
* binder can be used to add and configuration information in this environment. See {@link
* PrivateModule} for details.
*
* @return a binder that inherits configuration from this binder. Only exposed configuration on
* the returned binder will be visible to this binder.
*/
PrivateBinder newPrivateBinder();
/**
* Instructs the Injector that bindings must be listed in a Module in order to
* be injected. Classes that are not explicitly bound in a module cannot be
* injected. Bindings created through a linked binding
* (<code>bind(Foo.class).to(FooImpl.class)</code>) are allowed, but the
* implicit binding (<code>FooImpl</code>) cannot be directly injected unless
* it is also explicitly bound (<code>bind(FooImpl.class)</code>).
* <p>
* Tools can still retrieve bindings for implicit bindings (bindings created
* through a linked binding) if explicit bindings are required, however
* {@link Binding#getProvider} will fail.
* <p>
* By default, explicit bindings are not required.
* <p>
* If a parent injector requires explicit bindings, then all child injectors
* (and private modules within that injector) also require explicit bindings.
* If a parent does not require explicit bindings, a child injector or private
* module may optionally declare itself as requiring explicit bindings. If it
* does, the behavior is limited only to that child or any grandchildren. No
* siblings of the child will require explicit bindings.
* <p>
* In the absence of an explicit binding for the target, linked bindings in
* child injectors create a binding for the target in the parent. Since this
* behavior can be surprising, it causes an error instead if explicit bindings
* are required. To avoid this error, add an explicit binding for the target,
* either in the child or the parent.
*/
void requireExplicitBindings();
/**
* Prevents Guice from constructing a {@link Proxy} when a circular dependency
* is found. By default, circular proxies are not disabled.
* <p>
* If a parent injector disables circular proxies, then all child injectors
* (and private modules within that injector) also disable circular proxies.
* If a parent does not disable circular proxies, a child injector or private
* module may optionally declare itself as disabling circular proxies. If it
* does, the behavior is limited only to that child or any grandchildren. No
* siblings of the child will disable circular proxies.
*/
void disableCircularProxies();
/**
* Requires that a {@literal @}{@link Inject} annotation exists on a constructor in order for
* Guice to consider it an eligible injectable class. By default, Guice will inject classes that
* have a no-args constructor if no {@literal @}{@link Inject} annotation exists on any
* constructor.
* <p>
* If the class is bound using {@link LinkedBindingBuilder#toConstructor}, Guice will still inject
* that constructor regardless of annotations.
*/
void requireAtInjectOnConstructors();
/**
* Requires that Guice finds an exactly matching binding annotation. This disables the
* error-prone feature in Guice where it can substitute a binding for
* <code>{@literal @}Named Foo</code> when attempting to inject
* <code>{@literal @}Named("foo") Foo</code>.
*/
void requireExactBindingAnnotations();
/**
* Adds a scanner that will look in all installed modules for annotations the scanner can parse,
* and binds them like {@literal @}Provides methods. Scanners apply to all modules installed in
* the injector. Scanners installed in child injectors or private modules do not impact modules in
* siblings or parents, however scanners installed in parents do apply to all child injectors and
* private modules.
*/
void scanModulesForAnnotatedMethods(ModuleAnnotatedMethodScanner scanner);
}

View file

@ -0,0 +1,71 @@
package com.google.inject;
import com.google.inject.spi.BindingScopingVisitor;
import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.Element;
/**
* A mapping from a key (type and optional annotation) to the strategy for getting instances of the
* type. This interface is part of the introspection API and is intended primarily for use by
* tools.
*
* <p>Bindings are created in several ways:
* <ul>
* <li>Explicitly in a module, via {@code bind()} and {@code bindConstant()}
* statements:
* <pre>
* bind(Service.class).annotatedWith(Red.class).to(ServiceImpl.class);
* bindConstant().annotatedWith(ServerHost.class).to(args[0]);</pre></li>
* <li>Implicitly by the Injector by following a type's {@link ImplementedBy
* pointer} {@link ProvidedBy annotations} or by using its {@link Inject annotated} or
* default constructor.</li>
* <li>By converting a bound instance to a different type.</li>
* <li>For {@link Provider providers}, by delegating to the binding for the provided type.</li>
* </ul>
*
*
* <p>They exist on both modules and on injectors, and their behaviour is different for each:
* <ul>
* <li><strong>Module bindings</strong> are incomplete and cannot be used to provide instances.
* This is because the applicable scopes and interceptors may not be known until an injector
* is created. From a tool's perspective, module bindings are like the injector's source
* code. They can be inspected or rewritten, but this analysis must be done statically.</li>
* <li><strong>Injector bindings</strong> are complete and valid and can be used to provide
* instances. From a tools' perspective, injector bindings are like reflection for an
* injector. They have full runtime information, including the complete graph of injections
* necessary to satisfy a binding.</li>
* </ul>
*
* @param <T> the bound type. The injected is always assignable to this type.
*/
public interface Binding<T> extends Element {
/**
* Returns the key for this binding.
*/
Key<T> getKey();
/**
* Returns the scoped provider guice uses to fulfill requests for this
* binding.
*
* @throws UnsupportedOperationException when invoked on a {@link Binding}
* created via {@link com.google.inject.spi.Elements#getElements}. This
* method is only supported on {@link Binding}s returned from an injector.
*/
Provider<T> getProvider();
/**
* Accepts a target visitor. Invokes the visitor method specific to this binding's target.
*
* @param visitor to call back on
*/
<V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor);
/**
* Accepts a scoping visitor. Invokes the visitor method specific to this binding's scoping.
*
* @param visitor to call back on
*/
<V> V acceptScopingVisitor(BindingScopingVisitor<V> visitor);
}

View file

@ -0,0 +1,25 @@
package com.google.inject;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotates annotations which are used for binding. Only one such annotation
* may apply to a single injection point. You must also annotate binder
* annotations with {@code @Retention(RUNTIME)}. For example:
*
* <pre>
* {@code @}Retention(RUNTIME)
* {@code @}Target({ FIELD, PARAMETER, METHOD })
* {@code @}BindingAnnotation
* public {@code @}interface Transactional {}
* </pre>
*
*/
@Target(ANNOTATION_TYPE)
@Retention(RUNTIME)
public @interface BindingAnnotation {
}

View file

@ -0,0 +1,64 @@
package com.google.inject;
import com.google.common.collect.ImmutableSet;
import com.google.inject.internal.Errors;
import com.google.inject.spi.Message;
import java.util.Collection;
import static com.google.common.base.Preconditions.checkState;
/**
* Thrown when a programming error such as a misplaced annotation, illegal binding, or unsupported
* scope is found. Clients should catch this exception, log it, and stop execution.
*
*/
@SuppressWarnings("serial")
public final class ConfigurationException extends RuntimeException {
private final ImmutableSet<Message> messages;
private Object partialValue = null;
/**
* Creates a ConfigurationException containing {@code messages}.
*/
public ConfigurationException(Iterable<Message> messages) {
this.messages = ImmutableSet.copyOf(messages);
initCause(Errors.getOnlyCause(this.messages));
}
/**
* Returns a copy of this configuration exception with the specified partial value.
*/
public ConfigurationException withPartialValue(Object partialValue) {
checkState(this.partialValue == null,
"Can't clobber existing partial value %s with %s", this.partialValue, partialValue);
ConfigurationException result = new ConfigurationException(messages);
result.partialValue = partialValue;
return result;
}
/**
* Returns messages for the errors that caused this exception.
*/
public Collection<Message> getErrorMessages() {
return messages;
}
/**
* Returns a value that was only partially computed due to this exception. The caller can use
* this while collecting additional configuration problems.
*
* @return the partial value, or {@code null} if none was set. The type of the partial value is
* specified by the throwing method.
*/
@SuppressWarnings("unchecked") // this is *extremely* unsafe. We trust the caller here.
public <E> E getPartialValue() {
return (E) partialValue;
}
@Override
public String getMessage() {
return Errors.format("Guice configuration errors", messages);
}
}

View file

@ -0,0 +1,40 @@
package com.google.inject;
import com.google.common.collect.ImmutableSet;
import com.google.inject.internal.Errors;
import com.google.inject.spi.Message;
import java.util.Collection;
import static com.google.common.base.Preconditions.checkArgument;
/**
* Thrown when errors occur while creating a {@link Injector}. Includes a list of encountered
* errors. Clients should catch this exception, log it, and stop execution.
*/
public class CreationException extends RuntimeException {
private static final long serialVersionUID = 0;
private final ImmutableSet<Message> messages;
/**
* Creates a CreationException containing {@code messages}.
*/
public CreationException(Collection<Message> messages) {
this.messages = ImmutableSet.copyOf(messages);
checkArgument(!this.messages.isEmpty());
initCause(Errors.getOnlyCause(this.messages));
}
/**
* Returns messages for the errors that caused this exception.
*/
public Collection<Message> getErrorMessages() {
return messages;
}
@Override
public String getMessage() {
return Errors.format("Unable to create injector, see the following errors", messages);
}
}

View file

@ -0,0 +1,19 @@
package com.google.inject;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Acccompanies a {@literal @}{@link com.google.inject.Provides Provides} method annotation in a
* private module to indicate that the provided binding is exposed.
*
*/
@Target(ElementType.METHOD)
@Retention(RUNTIME)
@Documented
public @interface Exposed {
}

View file

@ -0,0 +1,86 @@
package com.google.inject;
import com.google.inject.internal.InternalInjectorCreator;
import java.util.Arrays;
/**
* The entry point to the Guice framework. Creates {@link Injector}s from
* {@link Module}s.
*
* <p>Guice supports a model of development that draws clear boundaries between
* APIs, Implementations of these APIs, Modules which configure these
* implementations, and finally Applications which consist of a collection of
* Modules. It is the Application, which typically defines your {@code main()}
* method, that bootstraps the Guice Injector using the {@code Guice} class, as
* in this example:
* <pre>
* public class FooApplication {
* public static void main(String[] args) {
* Injector injector = Guice.createInjector(
* new ModuleA(),
* new ModuleB(),
* . . .
* new FooApplicationFlagsModule(args)
* );
*
* // Now just bootstrap the application and you're done
* FooStarter starter = injector.getInstance(FooStarter.class);
* starter.runApplication();
* }
* }
* </pre>
*/
public final class Guice {
private Guice() {
}
/**
* Creates an injector for the given set of modules. This is equivalent to
* calling {@link #createInjector(Stage, Module...)} with Stage.DEVELOPMENT.
*
* @throws CreationException if one or more errors occur during injector
* construction
*/
public static Injector createInjector(Module... modules) {
return createInjector(Arrays.asList(modules));
}
/**
* Creates an injector for the given set of modules. This is equivalent to
* calling {@link #createInjector(Stage, Iterable)} with Stage.DEVELOPMENT.
*
* @throws CreationException if one or more errors occur during injector
* creation
*/
public static Injector createInjector(Iterable<? extends Module> modules) {
return createInjector(Stage.DEVELOPMENT, modules);
}
/**
* Creates an injector for the given set of modules, in a given development
* stage.
*
* @throws CreationException if one or more errors occur during injector
* creation.
*/
public static Injector createInjector(Stage stage, Module... modules) {
return createInjector(stage, Arrays.asList(modules));
}
/**
* Creates an injector for the given set of modules, in a given development
* stage.
*
* @throws CreationException if one or more errors occur during injector
* construction
*/
public static Injector createInjector(Stage stage,
Iterable<? extends Module> modules) {
return new InternalInjectorCreator()
.stage(stage)
.addModules(modules)
.build();
}
}

View file

@ -0,0 +1,20 @@
package com.google.inject;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* A pointer to the default implementation of a type.
*/
@Retention(RUNTIME)
@Target(TYPE)
public @interface ImplementedBy {
/**
* The implementation type.
*/
Class<?> value();
}

View file

@ -0,0 +1,51 @@
package com.google.inject;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotates members of your implementation class (constructors, methods
* and fields) into which the {@link Injector} should inject values.
* The Injector fulfills injection requests for:
*
* <ul>
* <li>Every instance it constructs. The class being constructed must have
* exactly one of its constructors marked with {@code @Inject} or must have a
* constructor taking no parameters. The Injector then proceeds to perform
* field and method injections.
*
* <li>Pre-constructed instances passed to {@link Injector#injectMembers},
* {@link com.google.inject.binder.LinkedBindingBuilder#toInstance(Object)} and
* {@link com.google.inject.binder.LinkedBindingBuilder#toProvider(javax.inject.Provider)}.
* In this case all constructors are, of course, ignored.
*
* <li>Static fields and methods of classes which any {@link Module} has
* specifically requested static injection for, using
* {@link Binder#requestStaticInjection}.
* </ul>
*
* In all cases, a member can be injected regardless of its Java access
* specifier (private, default, protected, public).
*/
@Target({METHOD, CONSTRUCTOR, FIELD})
@Retention(RUNTIME)
@Documented
public @interface Inject {
/**
* If true, and the appropriate binding is not found,
* the Injector will skip injection of this method or field rather than
* produce an error. When applied to a field, any default value already
* assigned to the field will remain (guice will not actively null out the
* field). When applied to a method, the method will only be invoked if
* bindings for <i>all</i> parameters are found. When applied to a
* constructor, an error will result upon Injector creation.
*/
boolean optional() default false;
}

View file

@ -0,0 +1,228 @@
package com.google.inject;
import com.google.inject.spi.TypeConverterBinding;
import java.lang.annotation.Annotation;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Builds the graphs of objects that make up your application. The injector tracks the dependencies
* for each type and uses bindings to inject them. This is the core of Guice, although you rarely
* interact with it directly. This "behind-the-scenes" operation is what distinguishes dependency
* injection from its cousin, the service locator pattern.
*
* <p>Contains several default bindings:
*
* <ul>
* <li>This {@link Injector} instance itself
* <li>A {@code Provider<T>} for each binding of type {@code T}
* <li>The {@link java.util.logging.Logger} for the class being injected
* <li>The {@link Stage} in which the Injector was created
* </ul>
*
* Injectors are created using the facade class {@link Guice}.
*
* <p>An injector can also {@link #injectMembers(Object) inject the dependencies} of
* already-constructed instances. This can be used to interoperate with objects created by other
* frameworks or services.
*
* <p>Injectors can be {@link #createChildInjector(Iterable) hierarchical}. Child injectors inherit
* the configuration of their parent injectors, but the converse does not hold.
*
* <p>The injector's {@link #getBindings() internal bindings} are available for introspection. This
* enables tools and extensions to operate on an injector reflectively.
*/
public interface Injector {
/**
* Injects dependencies into the fields and methods of {@code instance}. Ignores the presence or
* absence of an injectable constructor.
*
* <p>Whenever Guice creates an instance, it performs this injection automatically (after first
* performing constructor injection), so if you're able to let Guice create all your objects for
* you, you'll never need to use this method.
*
* @param instance to inject members on
* @see Binder#getMembersInjector(Class) for a preferred alternative that supports checks before
* run time
*/
void injectMembers(Object instance);
/**
* Returns the members injector used to inject dependencies into methods and fields on instances
* of the given type {@code T}.
*
* @param typeLiteral type to get members injector for
* @see Binder#getMembersInjector(TypeLiteral) for an alternative that offers up front error
* detection
*/
<T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral);
/**
* Returns the members injector used to inject dependencies into methods and fields on instances
* of the given type {@code T}. When feasible, use {@link Binder#getMembersInjector(TypeLiteral)}
* instead to get increased up front error detection.
*
* @param type type to get members injector for
* @see Binder#getMembersInjector(Class) for an alternative that offers up front error
* detection
*/
<T> MembersInjector<T> getMembersInjector(Class<T> type);
/**
* Returns this injector's <strong>explicit</strong> bindings.
*
* <p>The returned map does not include bindings inherited from a {@link #getParent() parent
* injector}, should one exist. The returned map is guaranteed to iterate (for example, with
* its {@link Map#entrySet()} iterator) in the order of insertion. In other words, the order in
* which bindings appear in user Modules.
*
* <p>This method is part of the Guice SPI and is intended for use by tools and extensions.
*/
Map<Key<?>, Binding<?>> getBindings();
/**
* Returns a snapshot of this injector's bindings, <strong>both explicit and
* just-in-time</strong>. The returned map is immutable; it contains only the bindings that were
* present when {@code getAllBindings()} was invoked. Subsequent calls may return a map with
* additional just-in-time bindings.
*
* <p>The returned map does not include bindings inherited from a {@link #getParent() parent
* injector}, should one exist.
*
* <p>This method is part of the Guice SPI and is intended for use by tools and extensions.
*/
Map<Key<?>, Binding<?>> getAllBindings();
/**
* Returns the binding for the given injection key. This will be an explicit bindings if the key
* was bound explicitly by a module, or an implicit binding otherwise. The implicit binding will
* be created if necessary.
*
* <p>This method is part of the Guice SPI and is intended for use by tools and extensions.
*
* @throws ConfigurationException if this injector cannot find or create the binding.
*/
<T> Binding<T> getBinding(Key<T> key);
/**
* Returns the binding for the given type. This will be an explicit bindings if the injection key
* was bound explicitly by a module, or an implicit binding otherwise. The implicit binding will
* be created if necessary.
*
* <p>This method is part of the Guice SPI and is intended for use by tools and extensions.
*
* @throws ConfigurationException if this injector cannot find or create the binding.
*/
<T> Binding<T> getBinding(Class<T> type);
/**
* Returns the binding if it already exists, or null if does not exist. Unlike
* {@link #getBinding(Key)}, this does not attempt to create just-in-time bindings
* for keys that aren't bound.
*
* <p> This method is part of the Guice SPI and is intended for use by tools and extensions.
*/
<T> Binding<T> getExistingBinding(Key<T> key);
/**
* Returns all explicit bindings for {@code type}.
*
* <p>This method is part of the Guice SPI and is intended for use by tools and extensions.
*/
<T> List<Binding<T>> findBindingsByType(TypeLiteral<T> type);
/**
* Returns the provider used to obtain instances for the given injection key. When feasible, avoid
* using this method, in favor of having Guice inject your dependencies ahead of time.
*
* @throws ConfigurationException if this injector cannot find or create the provider.
* @see Binder#getProvider(Key) for an alternative that offers up front error detection
*/
<T> Provider<T> getProvider(Key<T> key);
/**
* Returns the provider used to obtain instances for the given type. When feasible, avoid
* using this method, in favor of having Guice inject your dependencies ahead of time.
*
* @throws ConfigurationException if this injector cannot find or create the provider.
* @see Binder#getProvider(Class) for an alternative that offers up front error detection
*/
<T> Provider<T> getProvider(Class<T> type);
/**
* Returns the appropriate instance for the given injection key; equivalent to {@code
* getProvider(key).get()}. When feasible, avoid using this method, in favor of having Guice
* inject your dependencies ahead of time.
*
* @throws ConfigurationException if this injector cannot find or create the provider.
* @throws ProvisionException if there was a runtime failure while providing an instance.
*/
<T> T getInstance(Key<T> key);
/**
* Returns the appropriate instance for the given injection type; equivalent to {@code
* getProvider(type).get()}. When feasible, avoid using this method, in favor of having Guice
* inject your dependencies ahead of time.
*
* @throws ConfigurationException if this injector cannot find or create the provider.
* @throws ProvisionException if there was a runtime failure while providing an instance.
*/
<T> T getInstance(Class<T> type);
/**
* Returns this injector's parent, or {@code null} if this is a top-level injector.
*/
Injector getParent();
/**
* Returns a new injector that inherits all state from this injector. All bindings, scopes,
* interceptors and type converters are inherited -- they are visible to the child injector.
* Elements of the child injector are not visible to its parent.
*
* <p>Just-in-time bindings created for child injectors will be created in an ancestor injector
* whenever possible. This allows for scoped instances to be shared between injectors. Use
* explicit bindings to prevent bindings from being shared with the parent injector. Optional
* injections in just-in-time bindings (created in the parent injector) may be silently
* ignored if the optional dependencies are from the child injector.
*
* <p>No key may be bound by both an injector and one of its ancestors. This includes just-in-time
* bindings. The lone exception is the key for {@code Injector.class}, which is bound by each
* injector to itself.
*/
Injector createChildInjector(Iterable<? extends Module> modules);
/**
* Returns a new injector that inherits all state from this injector. All bindings, scopes,
* interceptors and type converters are inherited -- they are visible to the child injector.
* Elements of the child injector are not visible to its parent.
*
* <p>Just-in-time bindings created for child injectors will be created in an ancestor injector
* whenever possible. This allows for scoped instances to be shared between injectors. Use
* explicit bindings to prevent bindings from being shared with the parent injector.
*
* <p>No key may be bound by both an injector and one of its ancestors. This includes just-in-time
* bindings. The lone exception is the key for {@code Injector.class}, which is bound by each
* injector to itself.
*/
Injector createChildInjector(Module... modules);
/**
* Returns a map containing all scopes in the injector. The maps keys are scoping annotations
* like {@code Singleton.class}, and the values are scope instances, such as {@code
* Scopes.SINGLETON}. The returned map is immutable.
*
* <p>This method is part of the Guice SPI and is intended for use by tools and extensions.
*/
Map<Class<? extends Annotation>, Scope> getScopeBindings();
/**
* Returns a set containing all type converter bindings in the injector. The returned set is
* immutable.
*
* <p>This method is part of the Guice SPI and is intended for use by tools and extensions.
*/
Set<TypeConverterBinding> getTypeConverterBindings();
}

View file

@ -0,0 +1,508 @@
package com.google.inject;
import com.google.common.base.Supplier;
import com.google.common.base.Suppliers;
import com.google.inject.internal.Annotations;
import com.google.inject.internal.MoreTypes;
import java.lang.annotation.Annotation;
import java.lang.reflect.Type;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.inject.internal.Annotations.generateAnnotation;
import static com.google.inject.internal.Annotations.isAllDefaultMethods;
/**
* Binding key consisting of an injection type and an optional annotation.
* Matches the type and annotation at a point of injection.
*
* <p>For example, {@code Key.get(Service.class, Transactional.class)} will
* match:
*
* <pre>
* {@literal @}Inject
* public void setService({@literal @}Transactional Service service) {
* ...
* }
* </pre>
*
* <p>{@code Key} supports generic types via subclassing just like {@link
* TypeLiteral}.
*
* <p>Keys do not differentiate between primitive types (int, char, etc.) and
* their corresponding wrapper types (Integer, Character, etc.). Primitive
* types will be replaced with their wrapper types when keys are created.
*/
public class Key<T> {
private final AnnotationStrategy annotationStrategy;
private final TypeLiteral<T> typeLiteral;
private final int hashCode;
private final Supplier<String> toStringSupplier;
/**
* Constructs a new key. Derives the type from this class's type parameter.
*
* <p>Clients create an empty anonymous subclass. Doing so embeds the type
* parameter in the anonymous class's type hierarchy so we can reconstitute it
* at runtime despite erasure.
*
* <p>Example usage for a binding of type {@code Foo} annotated with
* {@code @Bar}:
*
* <p>{@code new Key<Foo>(Bar.class) {}}.
*/
@SuppressWarnings("unchecked")
protected Key(Class<? extends Annotation> annotationType) {
this.annotationStrategy = strategyFor(annotationType);
this.typeLiteral = MoreTypes.canonicalizeForKey(
(TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
this.hashCode = computeHashCode();
this.toStringSupplier = createToStringSupplier();
}
/**
* Constructs a new key. Derives the type from this class's type parameter.
*
* <p>Clients create an empty anonymous subclass. Doing so embeds the type
* parameter in the anonymous class's type hierarchy so we can reconstitute it
* at runtime despite erasure.
*
* <p>Example usage for a binding of type {@code Foo} annotated with
* {@code @Bar}:
*
* <p>{@code new Key<Foo>(new Bar()) {}}.
*/
@SuppressWarnings("unchecked")
protected Key(Annotation annotation) {
// no usages, not test-covered
this.annotationStrategy = strategyFor(annotation);
this.typeLiteral = MoreTypes.canonicalizeForKey(
(TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
this.hashCode = computeHashCode();
this.toStringSupplier = createToStringSupplier();
}
/**
* Constructs a new key. Derives the type from this class's type parameter.
*
* <p>Clients create an empty anonymous subclass. Doing so embeds the type
* parameter in the anonymous class's type hierarchy so we can reconstitute it
* at runtime despite erasure.
*
* <p>Example usage for a binding of type {@code Foo}:
*
* <p>{@code new Key<Foo>() {}}.
*/
@SuppressWarnings("unchecked")
protected Key() {
this.annotationStrategy = NullAnnotationStrategy.INSTANCE;
this.typeLiteral = MoreTypes.canonicalizeForKey(
(TypeLiteral<T>) TypeLiteral.fromSuperclassTypeParameter(getClass()));
this.hashCode = computeHashCode();
this.toStringSupplier = createToStringSupplier();
}
/**
* Unsafe. Constructs a key from a manually specified type.
*/
@SuppressWarnings("unchecked")
private Key(Type type, AnnotationStrategy annotationStrategy) {
this.annotationStrategy = annotationStrategy;
this.typeLiteral = MoreTypes.canonicalizeForKey((TypeLiteral<T>) TypeLiteral.get(type));
this.hashCode = computeHashCode();
this.toStringSupplier = createToStringSupplier();
}
/**
* Constructs a key from a manually specified type.
*/
private Key(TypeLiteral<T> typeLiteral, AnnotationStrategy annotationStrategy) {
this.annotationStrategy = annotationStrategy;
this.typeLiteral = MoreTypes.canonicalizeForKey(typeLiteral);
this.hashCode = computeHashCode();
this.toStringSupplier = createToStringSupplier();
}
/**
* Gets a key for an injection type and an annotation strategy.
*/
static <T> Key<T> get(Class<T> type,
AnnotationStrategy annotationStrategy) {
return new Key<T>(type, annotationStrategy);
}
/**
* Gets a key for an injection type.
*/
public static <T> Key<T> get(Class<T> type) {
return new Key<T>(type, NullAnnotationStrategy.INSTANCE);
}
/**
* Gets a key for an injection type and an annotation type.
*/
public static <T> Key<T> get(Class<T> type,
Class<? extends Annotation> annotationType) {
return new Key<T>(type, strategyFor(annotationType));
}
/**
* Gets a key for an injection type and an annotation.
*/
public static <T> Key<T> get(Class<T> type, Annotation annotation) {
return new Key<T>(type, strategyFor(annotation));
}
/**
* Gets a key for an injection type.
*/
public static Key<?> get(Type type) {
return new Key<Object>(type, NullAnnotationStrategy.INSTANCE);
}
/**
* Gets a key for an injection type and an annotation type.
*/
public static Key<?> get(Type type,
Class<? extends Annotation> annotationType) {
return new Key<Object>(type, strategyFor(annotationType));
}
/**
* Gets a key for an injection type and an annotation.
*/
public static Key<?> get(Type type, Annotation annotation) {
return new Key<Object>(type, strategyFor(annotation));
}
/**
* Gets a key for an injection type.
*/
public static <T> Key<T> get(TypeLiteral<T> typeLiteral) {
return new Key<T>(typeLiteral, NullAnnotationStrategy.INSTANCE);
}
/**
* Gets a key for an injection type and an annotation type.
*/
public static <T> Key<T> get(TypeLiteral<T> typeLiteral,
Class<? extends Annotation> annotationType) {
return new Key<T>(typeLiteral, strategyFor(annotationType));
}
/**
* Gets a key for an injection type and an annotation.
*/
public static <T> Key<T> get(TypeLiteral<T> typeLiteral,
Annotation annotation) {
return new Key<T>(typeLiteral, strategyFor(annotation));
}
/**
* Gets the strategy for an annotation.
*/
static AnnotationStrategy strategyFor(Annotation annotation) {
checkNotNull(annotation, "annotation");
Class<? extends Annotation> annotationType = annotation.annotationType();
ensureRetainedAtRuntime(annotationType);
ensureIsBindingAnnotation(annotationType);
if (Annotations.isMarker(annotationType)) {
return new AnnotationTypeStrategy(annotationType, annotation);
}
return new AnnotationInstanceStrategy(Annotations.canonicalizeIfNamed(annotation));
}
/**
* Gets the strategy for an annotation type.
*/
static AnnotationStrategy strategyFor(Class<? extends Annotation> annotationType) {
annotationType = Annotations.canonicalizeIfNamed(annotationType);
if (isAllDefaultMethods(annotationType)) {
return strategyFor(generateAnnotation(annotationType));
}
checkNotNull(annotationType, "annotation type");
ensureRetainedAtRuntime(annotationType);
ensureIsBindingAnnotation(annotationType);
return new AnnotationTypeStrategy(annotationType, null);
}
private static void ensureRetainedAtRuntime(
Class<? extends Annotation> annotationType) {
checkArgument(Annotations.isRetainedAtRuntime(annotationType),
"%s is not retained at runtime. Please annotate it with @Retention(RUNTIME).",
annotationType.getName());
}
private static void ensureIsBindingAnnotation(Class<? extends Annotation> annotationType) {
checkArgument(Annotations.isBindingAnnotation(annotationType),
"%s is not a binding annotation. Please annotate it with @BindingAnnotation.",
annotationType.getName());
}
/**
* Computes the hash code for this key.
*/
private int computeHashCode() {
return typeLiteral.hashCode() * 31 + annotationStrategy.hashCode();
}
/**
* @return a {@link Supplier} which memoizes the value for lazy initialization.
*/
private Supplier<String> createToStringSupplier() {
// The performance hit on access is acceptable since the intended use is for non-performance-
// critical applications.
return Suppliers.memoize(new Supplier<String>() {
@Override
public String get() {
return "Key[type=" + typeLiteral + ", annotation=" + annotationStrategy + "]";
}
});
}
/**
* Gets the key type.
*/
public final TypeLiteral<T> getTypeLiteral() {
return typeLiteral;
}
/**
* Gets the annotation type.
*/
public final Class<? extends Annotation> getAnnotationType() {
return annotationStrategy.getAnnotationType();
}
/**
* Gets the annotation.
*/
public final Annotation getAnnotation() {
return annotationStrategy.getAnnotation();
}
boolean hasAnnotationType() {
return annotationStrategy.getAnnotationType() != null;
}
String getAnnotationName() {
Annotation annotation = annotationStrategy.getAnnotation();
if (annotation != null) {
return annotation.toString();
}
// not test-covered
return annotationStrategy.getAnnotationType().toString();
}
Class<? super T> getRawType() {
return typeLiteral.getRawType();
}
/**
* Gets the key of this key's provider.
*/
Key<Provider<T>> providerKey() {
return ofType(typeLiteral.providerType());
}
@Override
public final boolean equals(Object o) {
if (o == this) {
return true;
}
if (!(o instanceof Key<?>)) {
return false;
}
Key<?> other = (Key<?>) o;
return annotationStrategy.equals(other.annotationStrategy)
&& typeLiteral.equals(other.typeLiteral);
}
@Override
public final int hashCode() {
return this.hashCode;
}
@Override
public final String toString() {
return toStringSupplier.get();
}
/**
* Returns a new key of the specified type with the same annotation as this
* key.
*/
public <T> Key<T> ofType(Class<T> type) {
return new Key<T>(type, annotationStrategy);
}
/**
* Returns a new key of the specified type with the same annotation as this
* key.
*/
public Key<?> ofType(Type type) {
return new Key<Object>(type, annotationStrategy);
}
/**
* Returns a new key of the specified type with the same annotation as this
* key.
*/
public <T> Key<T> ofType(TypeLiteral<T> type) {
return new Key<T>(type, annotationStrategy);
}
/**
* Returns true if this key has annotation attributes.
*/
public boolean hasAttributes() {
return annotationStrategy.hasAttributes();
}
/**
* Returns this key without annotation attributes, i.e. with only the
* annotation type.
*/
public Key<T> withoutAttributes() {
return new Key<T>(typeLiteral, annotationStrategy.withoutAttributes());
}
static enum NullAnnotationStrategy implements AnnotationStrategy {
INSTANCE;
public boolean hasAttributes() {
return false;
}
public AnnotationStrategy withoutAttributes() {
throw new UnsupportedOperationException("Key already has no attributes.");
}
public Annotation getAnnotation() {
return null;
}
public Class<? extends Annotation> getAnnotationType() {
return null;
}
@Override
public String toString() {
return "[none]";
}
}
interface AnnotationStrategy {
Annotation getAnnotation();
Class<? extends Annotation> getAnnotationType();
boolean hasAttributes();
AnnotationStrategy withoutAttributes();
}
// this class not test-covered
static class AnnotationInstanceStrategy implements AnnotationStrategy {
final Annotation annotation;
AnnotationInstanceStrategy(Annotation annotation) {
this.annotation = checkNotNull(annotation, "annotation");
}
public boolean hasAttributes() {
return true;
}
public AnnotationStrategy withoutAttributes() {
return new AnnotationTypeStrategy(getAnnotationType(), annotation);
}
public Annotation getAnnotation() {
return annotation;
}
public Class<? extends Annotation> getAnnotationType() {
return annotation.annotationType();
}
@Override
public boolean equals(Object o) {
if (!(o instanceof AnnotationInstanceStrategy)) {
return false;
}
AnnotationInstanceStrategy other = (AnnotationInstanceStrategy) o;
return annotation.equals(other.annotation);
}
@Override
public int hashCode() {
return annotation.hashCode();
}
@Override
public String toString() {
return annotation.toString();
}
}
static class AnnotationTypeStrategy implements AnnotationStrategy {
final Class<? extends Annotation> annotationType;
// Keep the instance around if we have it so the client can request it.
final Annotation annotation;
AnnotationTypeStrategy(Class<? extends Annotation> annotationType,
Annotation annotation) {
this.annotationType = checkNotNull(annotationType, "annotation type");
this.annotation = annotation;
}
public boolean hasAttributes() {
return false;
}
public AnnotationStrategy withoutAttributes() {
throw new UnsupportedOperationException("Key already has no attributes.");
}
public Annotation getAnnotation() {
return annotation;
}
public Class<? extends Annotation> getAnnotationType() {
return annotationType;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof AnnotationTypeStrategy)) {
return false;
}
AnnotationTypeStrategy other = (AnnotationTypeStrategy) o;
return annotationType.equals(other.annotationType);
}
@Override
public int hashCode() {
return annotationType.hashCode();
}
@Override
public String toString() {
return "@" + annotationType.getName();
}
}
}

View file

@ -0,0 +1,22 @@
package com.google.inject;
/**
* Injects dependencies into the fields and methods on instances of type {@code T}. Ignores the
* presence or absence of an injectable constructor.
*
* @param <T> type to inject members of
*/
public interface MembersInjector<T> {
/**
* Injects dependencies into the fields and methods of {@code instance}. Ignores the presence or
* absence of an injectable constructor.
*
* <p>Whenever Guice creates an instance, it performs this injection automatically (after first
* performing constructor injection), so if you're able to let Guice create all your objects for
* you, you'll never need to use this method.
*
* @param instance to inject members on. May be {@code null}.
*/
void injectMembers(T instance);
}

View file

@ -0,0 +1,27 @@
package com.google.inject;
/**
* A module contributes configuration information, typically interface
* bindings, which will be used to create an {@link Injector}. A Guice-based
* application is ultimately composed of little more than a set of
* {@code Module}s and some bootstrapping code.
*
* <p>Your Module classes can use a more streamlined syntax by extending
* {@link AbstractModule} rather than implementing this interface directly.
*
* <p>In addition to the bindings configured via {@link #configure}, bindings
* will be created for all methods annotated with {@literal @}{@link Provides}.
* Use scope and binding annotations on these methods to configure the
* bindings.
*/
public interface Module {
/**
* Contributes bindings and other configurations for this module to {@code binder}.
*
* <p><strong>Do not invoke this method directly</strong> to install submodules. Instead use
* {@link Binder#install(Module)}, which ensures that {@link Provides provider methods} are
* discovered.
*/
void configure(Binder binder);
}

View file

@ -0,0 +1,35 @@
package com.google.inject;
import com.google.inject.binder.AnnotatedElementBuilder;
/**
* Returns a binder whose configuration information is hidden from its environment by default. See
* {@link com.google.inject.PrivateModule PrivateModule} for details.
*
*/
public interface PrivateBinder extends Binder {
/**
* Makes the binding for {@code key} available to the enclosing environment
*/
void expose(Key<?> key);
/**
* Makes a binding for {@code type} available to the enclosing environment. Use {@link
* com.google.inject.binder.AnnotatedElementBuilder#annotatedWith(Class) annotatedWith()} to expose {@code type}
* with a
* binding annotation.
*/
AnnotatedElementBuilder expose(Class<?> type);
/**
* Makes a binding for {@code type} available to the enclosing environment. Use {@link
* AnnotatedElementBuilder#annotatedWith(Class) annotatedWith()} to expose {@code type} with a
* binding annotation.
*/
AnnotatedElementBuilder expose(TypeLiteral<?> type);
PrivateBinder withSource(Object source);
PrivateBinder skipSources(Class... classesToSkip);
}

View file

@ -0,0 +1,279 @@
package com.google.inject;
import com.google.inject.binder.AnnotatedBindingBuilder;
import com.google.inject.binder.AnnotatedConstantBindingBuilder;
import com.google.inject.binder.AnnotatedElementBuilder;
import com.google.inject.binder.LinkedBindingBuilder;
import com.google.inject.matcher.Matcher;
import com.google.inject.spi.Message;
import com.google.inject.spi.ProvisionListener;
import com.google.inject.spi.TypeConverter;
import com.google.inject.spi.TypeListener;
import java.lang.annotation.Annotation;
import static com.google.common.base.Preconditions.checkState;
/**
* A module whose configuration information is hidden from its environment by default. Only bindings
* that are explicitly exposed will be available to other modules and to the users of the injector.
* This module may expose the bindings it creates and the bindings of the modules it installs.
*
* <p>A private module can be nested within a regular module or within another private module using
* {@link Binder#install install()}. Its bindings live in a new environment that inherits bindings,
* type converters, scopes, and interceptors from the surrounding ("parent") environment. When you
* nest multiple private modules, the result is a tree of environments where the injector's
* environment is the root.
*
* <p>Guice EDSL bindings can be exposed with {@link #expose(Class) expose()}. {@literal @}{@link
* com.google.inject.Provides Provides} bindings can be exposed with the {@literal @}{@link
* Exposed} annotation:
*
* <pre>
* public class FooBarBazModule extends PrivateModule {
* protected void configure() {
* bind(Foo.class).to(RealFoo.class);
* expose(Foo.class);
*
* install(new TransactionalBarModule());
* expose(Bar.class).annotatedWith(Transactional.class);
*
* bind(SomeImplementationDetail.class);
* install(new MoreImplementationDetailsModule());
* }
*
* {@literal @}Provides {@literal @}Exposed
* public Baz provideBaz() {
* return new SuperBaz();
* }
* }
* </pre>
*
* <p>Private modules are implemented using {@link Injector#createChildInjector(Module[]) parent
* injectors}. When it can satisfy their dependencies, just-in-time bindings will be created in the
* root environment. Such bindings are shared among all environments in the tree.
*
* <p>The scope of a binding is constrained to its environment. A singleton bound in a private
* module will be unique to its environment. But a binding for the same type in a different private
* module will yield a different instance.
*
* <p>A shared binding that injects the {@code Injector} gets the root injector, which only has
* access to bindings in the root environment. An explicit binding that injects the {@code Injector}
* gets access to all bindings in the child environment.
*
* <p>To promote a just-in-time binding to an explicit binding, bind it:
* <pre>
* bind(FooImpl.class);
* </pre>
*
*/
public abstract class PrivateModule implements Module {
/**
* Like abstract module, the binder of the current private module
*/
private PrivateBinder binder;
public final synchronized void configure(Binder binder) {
checkState(this.binder == null, "Re-entry is not allowed.");
// Guice treats PrivateModules specially and passes in a PrivateBinder automatically.
this.binder = (PrivateBinder) binder.skipSources(PrivateModule.class);
try {
configure();
} finally {
this.binder = null;
}
}
/**
* Creates bindings and other configurations private to this module. Use {@link #expose(Class)
* expose()} to make the bindings in this module available externally.
*/
protected abstract void configure();
/**
* Makes the binding for {@code key} available to other modules and the injector.
*/
protected final <T> void expose(Key<T> key) {
binder().expose(key);
}
/**
* Makes a binding for {@code type} available to other modules and the injector. Use {@link
* AnnotatedElementBuilder#annotatedWith(Class) annotatedWith()} to expose {@code type} with a
* binding annotation.
*/
protected final AnnotatedElementBuilder expose(Class<?> type) {
return binder().expose(type);
}
/**
* Makes a binding for {@code type} available to other modules and the injector. Use {@link
* AnnotatedElementBuilder#annotatedWith(Class) annotatedWith()} to expose {@code type} with a
* binding annotation.
*/
protected final AnnotatedElementBuilder expose(TypeLiteral<?> type) {
return binder().expose(type);
}
// everything below is copied from AbstractModule
/**
* Returns the current binder.
*/
protected final PrivateBinder binder() {
checkState(binder != null, "The binder can only be used inside configure()");
return binder;
}
/**
* @see Binder#bindScope(Class, Scope)
*/
protected final void bindScope(Class<? extends Annotation> scopeAnnotation, Scope scope) {
binder().bindScope(scopeAnnotation, scope);
}
/**
* @see Binder#bind(Key)
*/
protected final <T> LinkedBindingBuilder<T> bind(Key<T> key) {
return binder().bind(key);
}
/**
* @see Binder#bind(TypeLiteral)
*/
protected final <T> AnnotatedBindingBuilder<T> bind(TypeLiteral<T> typeLiteral) {
return binder().bind(typeLiteral);
}
/**
* @see Binder#bind(Class)
*/
protected final <T> AnnotatedBindingBuilder<T> bind(Class<T> clazz) {
return binder().bind(clazz);
}
/**
* @see Binder#bindConstant()
*/
protected final AnnotatedConstantBindingBuilder bindConstant() {
return binder().bindConstant();
}
/**
* @see Binder#install(Module)
*/
protected final void install(Module module) {
binder().install(module);
}
/**
* @see Binder#addError(String, Object[])
*/
protected final void addError(String message, Object... arguments) {
binder().addError(message, arguments);
}
/**
* @see Binder#addError(Throwable)
*/
protected final void addError(Throwable t) {
binder().addError(t);
}
/**
* @see Binder#addError(Message)
*/
protected final void addError(Message message) {
binder().addError(message);
}
/**
* @see Binder#requestInjection(Object)
*/
protected final void requestInjection(Object instance) {
binder().requestInjection(instance);
}
/**
* @see Binder#requestStaticInjection(Class[])
*/
protected final void requestStaticInjection(Class<?>... types) {
binder().requestStaticInjection(types);
}
/**
* Instructs Guice to require a binding to the given key.
*/
protected final void requireBinding(Key<?> key) {
binder().getProvider(key);
}
/**
* Instructs Guice to require a binding to the given type.
*/
protected final void requireBinding(Class<?> type) {
binder().getProvider(type);
}
/**
* @see Binder#getProvider(Key)
*/
protected final <T> Provider<T> getProvider(Key<T> key) {
return binder().getProvider(key);
}
/**
* @see Binder#getProvider(Class)
*/
protected final <T> Provider<T> getProvider(Class<T> type) {
return binder().getProvider(type);
}
/**
* @see Binder#convertToTypes(com.google.inject.matcher.Matcher, com.google.inject.spi.TypeConverter)
*/
protected final void convertToTypes(Matcher<? super TypeLiteral<?>> typeMatcher,
TypeConverter converter) {
binder().convertToTypes(typeMatcher, converter);
}
/**
* @see Binder#currentStage()
*/
protected final Stage currentStage() {
return binder().currentStage();
}
/**
* @see Binder#getMembersInjector(Class)
*/
protected <T> MembersInjector<T> getMembersInjector(Class<T> type) {
return binder().getMembersInjector(type);
}
/**
* @see Binder#getMembersInjector(TypeLiteral)
*/
protected <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> type) {
return binder().getMembersInjector(type);
}
/**
* @see Binder#bindListener(com.google.inject.matcher.Matcher, com.google.inject.spi.TypeListener)
*/
protected void bindListener(Matcher<? super TypeLiteral<?>> typeMatcher,
TypeListener listener) {
binder().bindListener(typeMatcher, listener);
}
/**
* @see Binder#bindListener(Matcher, ProvisionListener...)
*/
protected void bindListener(Matcher<? super Binding<?>> bindingMatcher,
ProvisionListener... listeners) {
binder().bindListener(bindingMatcher, listeners);
}
}

View file

@ -0,0 +1,20 @@
package com.google.inject;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* A pointer to the default provider type for a type.
*/
@Retention(RUNTIME)
@Target(TYPE)
public @interface ProvidedBy {
/**
* The implementation type.
*/
Class<? extends Provider<?>> value();
}

View file

@ -0,0 +1,36 @@
package com.google.inject;
/**
* An object capable of providing instances of type {@code T}. Providers are used in numerous ways
* by Guice:
*
* <ul>
* <li>When the default means for obtaining instances (an injectable or parameterless constructor)
* is insufficient for a particular binding, the module can specify a custom {@code Provider}
* instead, to control exactly how Guice creates or obtains instances for the binding.
*
* <li>An implementation class may always choose to have a {@code Provider<T>} instance injected,
* rather than having a {@code T} injected directly. This may give you access to multiple
* instances, instances you wish to safely mutate and discard, instances which are out of scope
* (e.g. using a {@code @RequestScoped} object from within a {@code @SessionScoped} object), or
* instances that will be initialized lazily.
*
* <li>A custom {@link Scope} is implemented as a decorator of {@code Provider<T>}, which decides
* when to delegate to the backing provider and when to provide the instance some other way.
*
* <li>The {@link Injector} offers access to the {@code Provider<T>} it uses to fulfill requests
* for a given key, via the {@link Injector#getProvider} methods.
* </ul>
*
* @param <T> the type of object this provides
*/
public interface Provider<T> extends javax.inject.Provider<T> {
/**
* Provides an instance of {@code T}. Must never return {@code null}.
*
* @throws ProvisionException if an instance cannot be provided. Such exceptions include messages
* and throwables to describe why provision failed.
*/
T get();
}

View file

@ -0,0 +1,18 @@
package com.google.inject;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotates methods of a {@link Module} to create a provider method binding. The method's return
* type is bound to its returned value. Guice will pass dependencies to the method as parameters.
*/
@Documented
@Target(METHOD)
@Retention(RUNTIME)
public @interface Provides {
}

View file

@ -0,0 +1,49 @@
package com.google.inject;
import com.google.common.collect.ImmutableSet;
import com.google.inject.internal.Errors;
import com.google.inject.spi.Message;
import java.util.Collection;
import static com.google.common.base.Preconditions.checkArgument;
/**
* Indicates that there was a runtime failure while providing an instance.
*
*/
public final class ProvisionException extends RuntimeException {
private static final long serialVersionUID = 0;
private final ImmutableSet<Message> messages;
/**
* Creates a ProvisionException containing {@code messages}.
*/
public ProvisionException(Iterable<Message> messages) {
this.messages = ImmutableSet.copyOf(messages);
checkArgument(!this.messages.isEmpty());
initCause(Errors.getOnlyCause(this.messages));
}
public ProvisionException(String message, Throwable cause) {
super(cause);
this.messages = ImmutableSet.of(new Message(message, cause));
}
public ProvisionException(String message) {
this.messages = ImmutableSet.of(new Message(message));
}
/**
* Returns messages for the errors that caused this exception.
*/
public Collection<Message> getErrorMessages() {
return messages;
}
@Override
public String getMessage() {
return Errors.format("Unable to provision, see the following errors", messages);
}
}

View file

@ -0,0 +1,41 @@
package com.google.inject;
/**
* A scope is a level of visibility that instances provided by Guice may have.
* By default, an instance created by the {@link Injector} has <i>no scope</i>,
* meaning it has no state from the framework's perspective -- the
* {@code Injector} creates it, injects it once into the class that required it,
* and then immediately forgets it. Associating a scope with a particular
* binding allows the created instance to be "remembered" and possibly used
* again for other injections.
*
* <p>An example of a scope is {@link Scopes#SINGLETON}.
*/
public interface Scope {
/**
* Scopes a provider. The returned provider returns objects from this scope.
* If an object does not exist in this scope, the provider can use the given
* unscoped provider to retrieve one.
*
* <p>Scope implementations are strongly encouraged to override
* {@link Object#toString} in the returned provider and include the backing
* provider's {@code toString()} output.
*
* @param key binding key
* @param unscoped locates an instance when one doesn't already exist in this
* scope.
* @return a new provider which only delegates to the given unscoped provider
* when an instance of the requested object doesn't already exist in this
* scope
*/
public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped);
/**
* A short but useful description of this scope. For comparison, the standard
* scopes that ship with guice use the descriptions
* {@code "Scopes.SINGLETON"}, {@code "ServletScopes.SESSION"} and
* {@code "ServletScopes.REQUEST"}.
*/
String toString();
}

View file

@ -0,0 +1,24 @@
package com.google.inject;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Annotates annotations which are used for scoping. Only one such annotation
* may apply to a single implementation class. You must also annotate scope
* annotations with {@code @Retention(RUNTIME)}. For example:
*
* <pre>
* {@code @}Retention(RUNTIME)
* {@code @}Target(TYPE, METHOD)
* {@code @}ScopeAnnotation
* public {@code @}interface SessionScoped {}
* </pre>
*/
@Target(ANNOTATION_TYPE)
@Retention(RUNTIME)
public @interface ScopeAnnotation {
}

View file

@ -0,0 +1,162 @@
package com.google.inject;
import com.google.inject.internal.CircularDependencyProxy;
import com.google.inject.internal.LinkedBindingImpl;
import com.google.inject.internal.SingletonScope;
import com.google.inject.spi.BindingScopingVisitor;
import com.google.inject.spi.ExposedBinding;
import java.lang.annotation.Annotation;
/**
* Built-in scope implementations.
*/
public class Scopes {
/**
* One instance per {@link Injector}. Also see {@code @}{@link Singleton}.
*/
public static final Scope SINGLETON = new SingletonScope();
/**
* No scope; the same as not applying any scope at all. Each time the
* Injector obtains an instance of an object with "no scope", it injects this
* instance then immediately forgets it. When the next request for the same
* binding arrives it will need to obtain the instance over again.
*
* <p>This exists only in case a class has been annotated with a scope
* annotation such as {@link Singleton @Singleton}, and you need to override
* this to "no scope" in your binding.
*/
public static final Scope NO_SCOPE = new Scope() {
public <T> Provider<T> scope(Key<T> key, Provider<T> unscoped) {
return unscoped;
}
@Override
public String toString() {
return "Scopes.NO_SCOPE";
}
};
private static final BindingScopingVisitor<Boolean> IS_SINGLETON_VISITOR
= new BindingScopingVisitor<Boolean>() {
public Boolean visitNoScoping() {
return false;
}
public Boolean visitScopeAnnotation(Class<? extends Annotation> scopeAnnotation) {
return scopeAnnotation == Singleton.class
|| scopeAnnotation == javax.inject.Singleton.class;
}
public Boolean visitScope(Scope scope) {
return scope == Scopes.SINGLETON;
}
public Boolean visitEagerSingleton() {
return true;
}
};
private Scopes() {
}
/**
* Returns true if {@code binding} is singleton-scoped. If the binding is a {@link
* com.google.inject.spi.LinkedKeyBinding linked key binding} and belongs to an injector (ie. it
* was retrieved via {@link Injector#getBinding Injector.getBinding()}), then this method will
* also true if the target binding is singleton-scoped.
*/
public static boolean isSingleton(Binding<?> binding) {
do {
boolean singleton = binding.acceptScopingVisitor(IS_SINGLETON_VISITOR);
if (singleton) {
return true;
}
if (binding instanceof LinkedBindingImpl) {
LinkedBindingImpl<?> linkedBinding = (LinkedBindingImpl) binding;
Injector injector = linkedBinding.getInjector();
if (injector != null) {
binding = injector.getBinding(linkedBinding.getLinkedKey());
continue;
}
} else if (binding instanceof ExposedBinding) {
ExposedBinding<?> exposedBinding = (ExposedBinding) binding;
Injector injector = exposedBinding.getPrivateElements().getInjector();
if (injector != null) {
binding = injector.getBinding(exposedBinding.getKey());
continue;
}
}
return false;
} while (true);
}
/**
* Returns true if {@code binding} has the given scope. If the binding is a {@link
* com.google.inject.spi.LinkedKeyBinding linked key binding} and belongs to an injector (ie. it
* was retrieved via {@link Injector#getBinding Injector.getBinding()}), then this method will
* also true if the target binding has the given scope.
*
* @param binding binding to check
* @param scope scope implementation instance
* @param scopeAnnotation scope annotation class
*/
public static boolean isScoped(Binding<?> binding, final Scope scope,
final Class<? extends Annotation> scopeAnnotation) {
do {
boolean matches = binding.acceptScopingVisitor(new BindingScopingVisitor<Boolean>() {
public Boolean visitNoScoping() {
return false;
}
public Boolean visitScopeAnnotation(Class<? extends Annotation> visitedAnnotation) {
return visitedAnnotation == scopeAnnotation;
}
public Boolean visitScope(Scope visitedScope) {
return visitedScope == scope;
}
public Boolean visitEagerSingleton() {
return false;
}
});
if (matches) {
return true;
}
if (binding instanceof LinkedBindingImpl) {
LinkedBindingImpl<?> linkedBinding = (LinkedBindingImpl) binding;
Injector injector = linkedBinding.getInjector();
if (injector != null) {
binding = injector.getBinding(linkedBinding.getLinkedKey());
continue;
}
} else if (binding instanceof ExposedBinding) {
ExposedBinding<?> exposedBinding = (ExposedBinding) binding;
Injector injector = exposedBinding.getPrivateElements().getInjector();
if (injector != null) {
binding = injector.getBinding(exposedBinding.getKey());
continue;
}
}
return false;
} while (true);
}
/**
* Returns true if the object is a proxy for a circular dependency,
* constructed by Guice because it encountered a circular dependency. Scope
* implementations should be careful to <b>not cache circular proxies</b>,
* because the proxies are not intended for general purpose use. (They are
* designed just to fulfill the immediate injection, not all injections.
* Caching them can lead to IllegalArgumentExceptions or ClassCastExceptions.)
*/
public static boolean isCircularProxy(Object object) {
return object instanceof CircularDependencyProxy;
}
}

View file

@ -0,0 +1,17 @@
package com.google.inject;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
/**
* Apply this to implementation classes when you want only one instance
* (per {@link Injector}) to be reused for all injections for that binding.
*/
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RUNTIME)
@ScopeAnnotation
public @interface Singleton {
}

View file

@ -0,0 +1,26 @@
package com.google.inject;
/**
* The stage we're running in.
*/
public enum Stage {
/**
* We're running in a tool (an IDE plugin for example). We need binding meta data but not a
* functioning Injector. Do not inject members of instances. Do not load eager singletons. Do as
* little as possible so our tools run nice and snappy. Injectors created in this stage cannot
* be used to satisfy injections.
*/
TOOL,
/**
* We want fast startup times at the expense of runtime performance and some up front error
* checking.
*/
DEVELOPMENT,
/**
* We want to catch errors as early as possible and take performance hits up front.
*/
PRODUCTION
}

View file

@ -0,0 +1,321 @@
package com.google.inject;
import com.google.common.collect.ImmutableList;
import com.google.inject.internal.MoreTypes;
import com.google.inject.util.Types;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.List;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.inject.internal.MoreTypes.canonicalize;
/**
* Represents a generic type {@code T}. Java doesn't yet provide a way to
* represent generic types, so this class does. Forces clients to create a
* subclass of this class which enables retrieval the type information even at
* runtime.
*
* <p>For example, to create a type literal for {@code List<String>}, you can
* create an empty anonymous inner class:
*
* <p>
* {@code TypeLiteral<List<String>> list = new TypeLiteral<List<String>>() {};}
*
* <p>Along with modeling generic types, this class can resolve type parameters.
* For example, to figure out what type {@code keySet()} returns on a {@code
* Map<Integer, String>}, use this code:<pre> {@code
*
* TypeLiteral<Map<Integer, String>> mapType
* = new TypeLiteral<Map<Integer, String>>() {};
* TypeLiteral<?> keySetType
* = mapType.getReturnType(Map.class.getMethod("keySet"));
* System.out.println(keySetType); // prints "Set<Integer>"}</pre>
*
*/
public class TypeLiteral<T> {
final Class<? super T> rawType;
final Type type;
final int hashCode;
/**
* Constructs a new type literal. Derives represented class from type
* parameter.
*
* <p>Clients create an empty anonymous subclass. Doing so embeds the type
* parameter in the anonymous class's type hierarchy so we can reconstitute it
* at runtime despite erasure.
*/
@SuppressWarnings("unchecked")
protected TypeLiteral() {
this.type = getSuperclassTypeParameter(getClass());
this.rawType = (Class<? super T>) MoreTypes.getRawType(type);
this.hashCode = type.hashCode();
}
/**
* Unsafe. Constructs a type literal manually.
*/
@SuppressWarnings("unchecked")
TypeLiteral(Type type) {
this.type = canonicalize(checkNotNull(type, "type"));
this.rawType = (Class<? super T>) MoreTypes.getRawType(this.type);
this.hashCode = this.type.hashCode();
}
/**
* Returns the type from super class's type parameter in {@link MoreTypes#canonicalize(Type)
* canonical form}.
*/
static Type getSuperclassTypeParameter(Class<?> subclass) {
Type superclass = subclass.getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
ParameterizedType parameterized = (ParameterizedType) superclass;
return canonicalize(parameterized.getActualTypeArguments()[0]);
}
/**
* Gets type literal from super class's type parameter.
*/
static TypeLiteral<?> fromSuperclassTypeParameter(Class<?> subclass) {
return new TypeLiteral<Object>(getSuperclassTypeParameter(subclass));
}
/**
* Gets type literal for the given {@code Type} instance.
*/
public static TypeLiteral<?> get(Type type) {
return new TypeLiteral<Object>(type);
}
/**
* Gets type literal for the given {@code Class} instance.
*/
public static <T> TypeLiteral<T> get(Class<T> type) {
return new TypeLiteral<T>(type);
}
/**
* Returns the raw (non-generic) type for this type.
*
*/
public final Class<? super T> getRawType() {
return rawType;
}
/**
* Gets underlying {@code Type} instance.
*/
public final Type getType() {
return type;
}
/**
* Gets the type of this type's provider.
*/
@SuppressWarnings("unchecked")
final TypeLiteral<Provider<T>> providerType() {
// This cast is safe and wouldn't generate a warning if Type had a type
// parameter.
return (TypeLiteral<Provider<T>>) get(Types.providerOf(getType()));
}
@Override
public final int hashCode() {
return this.hashCode;
}
@Override
public final boolean equals(Object o) {
return o instanceof TypeLiteral<?>
&& MoreTypes.equals(type, ((TypeLiteral) o).type);
}
@Override
public final String toString() {
return MoreTypes.typeToString(type);
}
/**
* Returns an immutable list of the resolved types.
*/
private List<TypeLiteral<?>> resolveAll(Type[] types) {
TypeLiteral<?>[] result = new TypeLiteral<?>[types.length];
for (int t = 0; t < types.length; t++) {
result[t] = resolve(types[t]);
}
return ImmutableList.copyOf(result);
}
/**
* Resolves known type parameters in {@code toResolve} and returns the result.
*/
TypeLiteral<?> resolve(Type toResolve) {
return TypeLiteral.get(resolveType(toResolve));
}
Type resolveType(Type toResolve) {
// this implementation is made a little more complicated in an attempt to avoid object-creation
while (true) {
if (toResolve instanceof TypeVariable) {
TypeVariable original = (TypeVariable) toResolve;
toResolve = MoreTypes.resolveTypeVariable(type, rawType, original);
if (toResolve == original) {
return toResolve;
}
} else if (toResolve instanceof GenericArrayType) {
GenericArrayType original = (GenericArrayType) toResolve;
Type componentType = original.getGenericComponentType();
Type newComponentType = resolveType(componentType);
return componentType == newComponentType
? original
: Types.arrayOf(newComponentType);
} else if (toResolve instanceof ParameterizedType) {
ParameterizedType original = (ParameterizedType) toResolve;
Type ownerType = original.getOwnerType();
Type newOwnerType = resolveType(ownerType);
boolean changed = newOwnerType != ownerType;
Type[] args = original.getActualTypeArguments();
for (int t = 0, length = args.length; t < length; t++) {
Type resolvedTypeArgument = resolveType(args[t]);
if (resolvedTypeArgument != args[t]) {
if (!changed) {
args = args.clone();
changed = true;
}
args[t] = resolvedTypeArgument;
}
}
return changed
? Types.newParameterizedTypeWithOwner(newOwnerType, original.getRawType(), args)
: original;
} else if (toResolve instanceof WildcardType) {
WildcardType original = (WildcardType) toResolve;
Type[] originalLowerBound = original.getLowerBounds();
Type[] originalUpperBound = original.getUpperBounds();
if (originalLowerBound.length == 1) {
Type lowerBound = resolveType(originalLowerBound[0]);
if (lowerBound != originalLowerBound[0]) {
return Types.supertypeOf(lowerBound);
}
} else if (originalUpperBound.length == 1) {
Type upperBound = resolveType(originalUpperBound[0]);
if (upperBound != originalUpperBound[0]) {
return Types.subtypeOf(upperBound);
}
}
return original;
} else {
return toResolve;
}
}
}
/**
* Returns the generic form of {@code supertype}. For example, if this is {@code
* ArrayList<String>}, this returns {@code Iterable<String>} given the input {@code
* Iterable.class}.
*
* @param supertype a superclass of, or interface implemented by, this.
*/
public TypeLiteral<?> getSupertype(Class<?> supertype) {
checkArgument(supertype.isAssignableFrom(rawType),
"%s is not a supertype of %s", supertype, this.type);
return resolve(MoreTypes.getGenericSupertype(type, rawType, supertype));
}
/**
* Returns the resolved generic type of {@code field}.
*
* @param field a field defined by this or any superclass.
*/
public TypeLiteral<?> getFieldType(Field field) {
checkArgument(field.getDeclaringClass().isAssignableFrom(rawType),
"%s is not defined by a supertype of %s", field, type);
return resolve(field.getGenericType());
}
/**
* Returns the resolved generic parameter types of {@code methodOrConstructor}.
*
* @param methodOrConstructor a method or constructor defined by this or any supertype.
*/
public List<TypeLiteral<?>> getParameterTypes(Member methodOrConstructor) {
Type[] genericParameterTypes;
if (methodOrConstructor instanceof Method) {
Method method = (Method) methodOrConstructor;
checkArgument(method.getDeclaringClass().isAssignableFrom(rawType),
"%s is not defined by a supertype of %s", method, type);
genericParameterTypes = method.getGenericParameterTypes();
} else if (methodOrConstructor instanceof Constructor) {
Constructor<?> constructor = (Constructor<?>) methodOrConstructor;
checkArgument(constructor.getDeclaringClass().isAssignableFrom(rawType),
"%s does not construct a supertype of %s", constructor, type);
genericParameterTypes = constructor.getGenericParameterTypes();
} else {
throw new IllegalArgumentException("Not a method or a constructor: " + methodOrConstructor);
}
return resolveAll(genericParameterTypes);
}
/**
* Returns the resolved generic exception types thrown by {@code constructor}.
*
* @param methodOrConstructor a method or constructor defined by this or any supertype.
*/
public List<TypeLiteral<?>> getExceptionTypes(Member methodOrConstructor) {
Type[] genericExceptionTypes;
if (methodOrConstructor instanceof Method) {
Method method = (Method) methodOrConstructor;
checkArgument(method.getDeclaringClass().isAssignableFrom(rawType),
"%s is not defined by a supertype of %s", method, type);
genericExceptionTypes = method.getGenericExceptionTypes();
} else if (methodOrConstructor instanceof Constructor) {
Constructor<?> constructor = (Constructor<?>) methodOrConstructor;
checkArgument(constructor.getDeclaringClass().isAssignableFrom(rawType),
"%s does not construct a supertype of %s", constructor, type);
genericExceptionTypes = constructor.getGenericExceptionTypes();
} else {
throw new IllegalArgumentException("Not a method or a constructor: " + methodOrConstructor);
}
return resolveAll(genericExceptionTypes);
}
/**
* Returns the resolved generic return type of {@code method}.
*
* @param method a method defined by this or any supertype.
*/
public TypeLiteral<?> getReturnType(Method method) {
checkArgument(method.getDeclaringClass().isAssignableFrom(rawType),
"%s is not defined by a supertype of %s", method, type);
return resolve(method.getGenericReturnType());
}
}

View file

@ -0,0 +1,20 @@
package com.google.inject.binder;
import java.lang.annotation.Annotation;
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*/
public interface AnnotatedBindingBuilder<T> extends LinkedBindingBuilder<T> {
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*/
LinkedBindingBuilder<T> annotatedWith(
Class<? extends Annotation> annotationType);
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*/
LinkedBindingBuilder<T> annotatedWith(Annotation annotation);
}

View file

@ -0,0 +1,20 @@
package com.google.inject.binder;
import java.lang.annotation.Annotation;
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*/
public interface AnnotatedConstantBindingBuilder {
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*/
ConstantBindingBuilder annotatedWith(
Class<? extends Annotation> annotationType);
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*/
ConstantBindingBuilder annotatedWith(Annotation annotation);
}

View file

@ -0,0 +1,19 @@
package com.google.inject.binder;
import java.lang.annotation.Annotation;
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*/
public interface AnnotatedElementBuilder {
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*/
void annotatedWith(Class<? extends Annotation> annotationType);
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*/
void annotatedWith(Annotation annotation);
}

View file

@ -0,0 +1,62 @@
package com.google.inject.binder;
/**
* Binds to a constant value.
*/
public interface ConstantBindingBuilder {
/**
* Binds constant to the given value.
*/
void to(String value);
/**
* Binds constant to the given value.
*/
void to(int value);
/**
* Binds constant to the given value.
*/
void to(long value);
/**
* Binds constant to the given value.
*/
void to(boolean value);
/**
* Binds constant to the given value.
*/
void to(double value);
/**
* Binds constant to the given value.
*/
void to(float value);
/**
* Binds constant to the given value.
*/
void to(short value);
/**
* Binds constant to the given value.
*/
void to(char value);
/**
* Binds constant to the given value.
*/
void to(byte value);
/**
* Binds constant to the given value.
*/
void to(Class<?> value);
/**
* Binds constant to the given value.
*/
<E extends Enum<E>> void to(E value);
}

View file

@ -0,0 +1,79 @@
package com.google.inject.binder;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
import java.lang.reflect.Constructor;
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*
*/
public interface LinkedBindingBuilder<T> extends ScopedBindingBuilder {
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*/
ScopedBindingBuilder to(Class<? extends T> implementation);
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*/
ScopedBindingBuilder to(TypeLiteral<? extends T> implementation);
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*/
ScopedBindingBuilder to(Key<? extends T> targetKey);
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*
* @see com.google.inject.Injector#injectMembers
*/
void toInstance(T instance);
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*
* @see com.google.inject.Injector#injectMembers
*/
ScopedBindingBuilder toProvider(Provider<? extends T> provider);
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*
* @see com.google.inject.Injector#injectMembers
*/
ScopedBindingBuilder toProvider(javax.inject.Provider<? extends T> provider);
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*/
ScopedBindingBuilder toProvider(
Class<? extends javax.inject.Provider<? extends T>> providerType);
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*/
ScopedBindingBuilder toProvider(
TypeLiteral<? extends javax.inject.Provider<? extends T>> providerType);
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*/
ScopedBindingBuilder toProvider(
Key<? extends javax.inject.Provider<? extends T>> providerKey);
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*/
<S extends T> ScopedBindingBuilder toConstructor(Constructor<S> constructor);
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*/
<S extends T> ScopedBindingBuilder toConstructor(
Constructor<S> constructor, TypeLiteral<? extends S> type);
}

View file

@ -0,0 +1,29 @@
package com.google.inject.binder;
import com.google.inject.Scope;
import java.lang.annotation.Annotation;
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*/
public interface ScopedBindingBuilder {
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*/
void in(Class<? extends Annotation> scopeAnnotation);
/**
* See the EDSL examples at {@link com.google.inject.Binder}.
*/
void in(Scope scope);
/**
* Instructs the {@link com.google.inject.Injector} to eagerly initialize this
* singleton-scoped binding upon creation. Useful for application
* initialization logic. See the EDSL examples at
* {@link com.google.inject.Binder}.
*/
void asEagerSingleton();
}

View file

@ -0,0 +1,118 @@
package com.google.inject.internal;
import com.google.inject.Binder;
import com.google.inject.Key;
import com.google.inject.Scope;
import com.google.inject.spi.Element;
import com.google.inject.spi.InstanceBinding;
import java.lang.annotation.Annotation;
import java.util.List;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Bind a value or constant.
*
*/
public abstract class AbstractBindingBuilder<T> {
public static final String IMPLEMENTATION_ALREADY_SET = "Implementation is set more than once.";
public static final String SINGLE_INSTANCE_AND_SCOPE
= "Setting the scope is not permitted when binding to a single instance.";
public static final String SCOPE_ALREADY_SET = "Scope is set more than once.";
public static final String BINDING_TO_NULL = "Binding to null instances is not allowed. "
+ "Use toProvider(Providers.of(null)) if this is your intended behaviour.";
public static final String CONSTANT_VALUE_ALREADY_SET = "Constant value is set more than once.";
public static final String ANNOTATION_ALREADY_SPECIFIED
= "More than one annotation is specified for this binding.";
protected static final Key<?> NULL_KEY = Key.get(Void.class);
protected final Binder binder;
protected List<Element> elements;
protected int position;
private BindingImpl<T> binding;
public AbstractBindingBuilder(Binder binder, List<Element> elements, Object source, Key<T> key) {
this.binder = binder;
this.elements = elements;
this.position = elements.size();
this.binding = new UntargettedBindingImpl<T>(source, key, Scoping.UNSCOPED);
elements.add(position, this.binding);
}
protected BindingImpl<T> getBinding() {
return binding;
}
protected BindingImpl<T> setBinding(BindingImpl<T> binding) {
this.binding = binding;
elements.set(position, binding);
return binding;
}
/**
* Sets the binding to a copy with the specified annotation on the bound key
*/
protected BindingImpl<T> annotatedWithInternal(Class<? extends Annotation> annotationType) {
checkNotNull(annotationType, "annotationType");
checkNotAnnotated();
return setBinding(binding.withKey(
Key.get(this.binding.getKey().getTypeLiteral(), annotationType)));
}
/**
* Sets the binding to a copy with the specified annotation on the bound key
*/
protected BindingImpl<T> annotatedWithInternal(Annotation annotation) {
checkNotNull(annotation, "annotation");
checkNotAnnotated();
return setBinding(binding.withKey(
Key.get(this.binding.getKey().getTypeLiteral(), annotation)));
}
public void in(final Class<? extends Annotation> scopeAnnotation) {
checkNotNull(scopeAnnotation, "scopeAnnotation");
checkNotScoped();
setBinding(getBinding().withScoping(Scoping.forAnnotation(scopeAnnotation)));
}
public void in(final Scope scope) {
checkNotNull(scope, "scope");
checkNotScoped();
setBinding(getBinding().withScoping(Scoping.forInstance(scope)));
}
public void asEagerSingleton() {
checkNotScoped();
setBinding(getBinding().withScoping(Scoping.EAGER_SINGLETON));
}
protected boolean keyTypeIsSet() {
return !Void.class.equals(binding.getKey().getTypeLiteral().getType());
}
protected void checkNotTargetted() {
if (!(binding instanceof UntargettedBindingImpl)) {
binder.addError(IMPLEMENTATION_ALREADY_SET);
}
}
protected void checkNotAnnotated() {
if (binding.getKey().getAnnotationType() != null) {
binder.addError(ANNOTATION_ALREADY_SPECIFIED);
}
}
protected void checkNotScoped() {
// Scoping isn't allowed when we have only one instance.
if (binding instanceof InstanceBinding) {
binder.addError(SINGLE_INSTANCE_AND_SCOPE);
return;
}
if (binding.getScoping().isExplicitlyScoped()) {
binder.addError(SCOPE_ALREADY_SET);
}
}
}

View file

@ -0,0 +1,146 @@
package com.google.inject.internal;
import com.google.common.collect.ImmutableSet;
import com.google.inject.AbstractModule;
import com.google.inject.Binder;
import com.google.inject.Binding;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.MembersInjector;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.Scope;
import com.google.inject.Stage;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.DefaultBindingTargetVisitor;
import java.util.Set;
/**
* Guarantees that processing of Binding elements happens in a sane way.
*/
abstract class AbstractBindingProcessor extends AbstractProcessor {
// It's unfortunate that we have to maintain a blacklist of specific
// classes, but we can't easily block the whole package because of
// all our unit tests.
private static final Set<Class<?>> FORBIDDEN_TYPES = ImmutableSet.<Class<?>>of(
AbstractModule.class,
Binder.class,
Binding.class,
Injector.class,
Key.class,
MembersInjector.class,
Module.class,
Provider.class,
Scope.class,
Stage.class,
TypeLiteral.class);
protected final ProcessedBindingData bindingData;
AbstractBindingProcessor(Errors errors, ProcessedBindingData bindingData) {
super(errors);
this.bindingData = bindingData;
}
protected <T> UntargettedBindingImpl<T> invalidBinding(
InjectorImpl injector, Key<T> key, Object source) {
return new UntargettedBindingImpl<T>(injector, key, source);
}
protected void putBinding(BindingImpl<?> binding) {
Key<?> key = binding.getKey();
Class<?> rawType = key.getTypeLiteral().getRawType();
if (FORBIDDEN_TYPES.contains(rawType)) {
errors.cannotBindToGuiceType(rawType.getSimpleName());
return;
}
BindingImpl<?> original = injector.getExistingBinding(key);
if (original != null) {
// If it failed because of an explicit duplicate binding...
if (injector.state.getExplicitBinding(key) != null) {
try {
if (!isOkayDuplicate(original, binding, injector.state)) {
errors.bindingAlreadySet(key, original.getSource());
return;
}
} catch (Throwable t) {
errors.errorCheckingDuplicateBinding(key, original.getSource(), t);
return;
}
} else {
// Otherwise, it failed because of a duplicate JIT binding
// in the parent
errors.jitBindingAlreadySet(key);
return;
}
}
// prevent the parent from creating a JIT binding for this key
injector.state.parent().blacklist(key, injector.state, binding.getSource());
injector.state.putBinding(key, binding);
}
/**
* We tolerate duplicate bindings if one exposes the other or if the two bindings
* are considered duplicates.
*
* @param original the binding in the parent injector (candidate for an exposing binding)
* @param binding the binding to check (candidate for the exposed binding)
*/
private boolean isOkayDuplicate(BindingImpl<?> original, BindingImpl<?> binding, State state) {
if (original instanceof ExposedBindingImpl) {
ExposedBindingImpl exposed = (ExposedBindingImpl) original;
InjectorImpl exposedFrom = (InjectorImpl) exposed.getPrivateElements().getInjector();
return (exposedFrom == binding.getInjector());
} else {
original = (BindingImpl<?>) state.getExplicitBindingsThisLevel().get(binding.getKey());
// If no original at this level, the original was on a parent, and we don't
// allow deduplication between parents & children.
return original != null && original.equals(binding);
}
}
private <T> void validateKey(Object source, Key<T> key) {
Annotations.checkForMisplacedScopeAnnotations(
key.getTypeLiteral().getRawType(), source, errors);
}
/**
* Processor for visiting bindings. Each overriden method that wants to
* actually process the binding should call prepareBinding first.
*/
abstract class Processor<T, V> extends DefaultBindingTargetVisitor<T, V> {
final Object source;
final Key<T> key;
final Class<? super T> rawType;
Scoping scoping;
Processor(BindingImpl<T> binding) {
source = binding.getSource();
key = binding.getKey();
rawType = key.getTypeLiteral().getRawType();
scoping = binding.getScoping();
}
protected void prepareBinding() {
validateKey(source, key);
scoping = Scoping.makeInjectable(scoping, injector, errors);
}
protected void scheduleInitialization(final BindingImpl<?> binding) {
bindingData.addUninitializedBinding(new Runnable() {
public void run() {
try {
binding.getInjector().initializeBinding(binding, errors.withSource(source));
} catch (ErrorsException e) {
errors.merge(e.getErrors());
}
}
});
}
}
}

View file

@ -0,0 +1,54 @@
package com.google.inject.internal;
import com.google.inject.spi.DefaultElementVisitor;
import com.google.inject.spi.Element;
import java.util.Iterator;
import java.util.List;
/**
* Abstract base class for creating an injector from module elements.
*
* <p>Extending classes must return {@code true} from any overridden
* {@code visit*()} methods, in order for the element processor to remove the
* handled element.
*
*/
abstract class AbstractProcessor extends DefaultElementVisitor<Boolean> {
protected Errors errors;
protected InjectorImpl injector;
protected AbstractProcessor(Errors errors) {
this.errors = errors;
}
public void process(Iterable<InjectorShell> isolatedInjectorBuilders) {
for (InjectorShell injectorShell : isolatedInjectorBuilders) {
process(injectorShell.getInjector(), injectorShell.getElements());
}
}
public void process(InjectorImpl injector, List<Element> elements) {
Errors errorsAnyElement = this.errors;
this.injector = injector;
try {
for (Iterator<Element> i = elements.iterator(); i.hasNext(); ) {
Element element = i.next();
this.errors = errorsAnyElement.withSource(element.getSource());
Boolean allDone = element.acceptVisitor(this);
if (allDone) {
i.remove();
}
}
} finally {
this.errors = errorsAnyElement;
this.injector = null;
}
}
@Override
protected Boolean visitOther(Element element) {
return false;
}
}

View file

@ -0,0 +1,334 @@
package com.google.inject.internal;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.base.Joiner.MapJoiner;
import com.google.common.base.Preconditions;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Maps;
import com.google.inject.BindingAnnotation;
import com.google.inject.Key;
import com.google.inject.ScopeAnnotation;
import com.google.inject.TypeLiteral;
import com.google.inject.internal.util.Classes;
import com.google.inject.name.Named;
import com.google.inject.name.Names;
import javax.inject.Qualifier;
import java.lang.annotation.Annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import java.util.Collection;
import java.util.Map;
/**
* Annotation utilities.
*
*/
public class Annotations {
private static final MapJoiner JOINER = Joiner.on(", ").withKeyValueSeparator("=");
private static final Function<Object, String> DEEP_TO_STRING_FN = new Function<Object, String>() {
@Override
public String apply(Object arg) {
String s = Arrays.deepToString(new Object[]{arg});
return s.substring(1, s.length() - 1); // cut off brackets
}
};
private static final LoadingCache<Class<? extends Annotation>, Annotation> cache =
CacheBuilder.newBuilder().weakKeys().build(
new CacheLoader<Class<? extends Annotation>, Annotation>() {
@Override
public Annotation load(Class<? extends Annotation> input) {
return generateAnnotationImpl(input);
}
});
private static final AnnotationChecker scopeChecker = new AnnotationChecker(
Arrays.asList(ScopeAnnotation.class, javax.inject.Scope.class));
private static final AnnotationChecker bindingAnnotationChecker = new AnnotationChecker(
Arrays.asList(BindingAnnotation.class, Qualifier.class));
/**
* Returns {@code true} if the given annotation type has no attributes.
*/
public static boolean isMarker(Class<? extends Annotation> annotationType) {
return annotationType.getDeclaredMethods().length == 0;
}
public static boolean isAllDefaultMethods(Class<? extends Annotation> annotationType) {
boolean hasMethods = false;
for (Method m : annotationType.getDeclaredMethods()) {
hasMethods = true;
if (m.getDefaultValue() == null) {
return false;
}
}
return hasMethods;
}
/**
* Generates an Annotation for the annotation class. Requires that the annotation is all
* optionals.
*/
@SuppressWarnings("unchecked")
public static <T extends Annotation> T generateAnnotation(Class<T> annotationType) {
Preconditions.checkState(
isAllDefaultMethods(annotationType), "%s is not all default methods", annotationType);
return (T) cache.getUnchecked(annotationType);
}
private static <T extends Annotation> T generateAnnotationImpl(final Class<T> annotationType) {
final Map<String, Object> members = resolveMembers(annotationType);
return annotationType.cast(Proxy.newProxyInstance(
annotationType.getClassLoader(),
new Class<?>[]{annotationType},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Exception {
String name = method.getName();
if (name.equals("annotationType")) {
return annotationType;
} else if (name.equals("toString")) {
return annotationToString(annotationType, members);
} else if (name.equals("hashCode")) {
return annotationHashCode(annotationType, members);
} else if (name.equals("equals")) {
return annotationEquals(annotationType, members, args[0]);
} else {
return members.get(name);
}
}
}));
}
private static ImmutableMap<String, Object> resolveMembers(
Class<? extends Annotation> annotationType) {
ImmutableMap.Builder<String, Object> result = ImmutableMap.builder();
for (Method method : annotationType.getDeclaredMethods()) {
result.put(method.getName(), method.getDefaultValue());
}
return result.build();
}
/**
* Implements {@link Annotation#equals}.
*/
private static boolean annotationEquals(Class<? extends Annotation> type,
Map<String, Object> members, Object other) throws Exception {
if (!type.isInstance(other)) {
return false;
}
for (Method method : type.getDeclaredMethods()) {
String name = method.getName();
if (!Arrays.deepEquals(
new Object[]{method.invoke(other)}, new Object[]{members.get(name)})) {
return false;
}
}
return true;
}
/**
* Implements {@link Annotation#hashCode}.
*/
private static int annotationHashCode(Class<? extends Annotation> type,
Map<String, Object> members) throws Exception {
int result = 0;
for (Method method : type.getDeclaredMethods()) {
String name = method.getName();
Object value = members.get(name);
result += (127 * name.hashCode()) ^ (Arrays.deepHashCode(new Object[]{value}) - 31);
}
return result;
}
/**
* Implements {@link Annotation#toString}.
*/
private static String annotationToString(Class<? extends Annotation> type,
Map<String, Object> members) throws Exception {
StringBuilder sb = new StringBuilder().append("@").append(type.getName()).append("(");
JOINER.appendTo(sb, Maps.transformValues(members, DEEP_TO_STRING_FN));
return sb.append(")").toString();
}
/**
* Returns true if the given annotation is retained at runtime.
*/
public static boolean isRetainedAtRuntime(Class<? extends Annotation> annotationType) {
Retention retention = annotationType.getAnnotation(Retention.class);
return retention != null && retention.value() == RetentionPolicy.RUNTIME;
}
/**
* Returns the scope annotation on {@code type}, or null if none is specified.
*/
public static Class<? extends Annotation> findScopeAnnotation(
Errors errors, Class<?> implementation) {
return findScopeAnnotation(errors, implementation.getAnnotations());
}
/**
* Returns the scoping annotation, or null if there isn't one.
*/
public static Class<? extends Annotation> findScopeAnnotation(Errors errors, Annotation[] annotations) {
Class<? extends Annotation> found = null;
for (Annotation annotation : annotations) {
Class<? extends Annotation> annotationType = annotation.annotationType();
if (isScopeAnnotation(annotationType)) {
if (found != null) {
errors.duplicateScopeAnnotations(found, annotationType);
} else {
found = annotationType;
}
}
}
return found;
}
static boolean containsComponentAnnotation(Annotation[] annotations) {
for (Annotation annotation : annotations) {
// TODO(user): Should we scope this down to dagger.Component?
if (annotation.annotationType().getSimpleName().equals("Component")) {
return true;
}
}
return false;
}
public static boolean isScopeAnnotation(Class<? extends Annotation> annotationType) {
return scopeChecker.hasAnnotations(annotationType);
}
/**
* Adds an error if there is a misplaced annotations on {@code type}. Scoping
* annotations are not allowed on abstract classes or interfaces.
*/
public static void checkForMisplacedScopeAnnotations(
Class<?> type, Object source, Errors errors) {
if (Classes.isConcrete(type)) {
return;
}
Class<? extends Annotation> scopeAnnotation = findScopeAnnotation(errors, type);
if (scopeAnnotation != null
// We let Dagger Components through to aid migrations.
&& !containsComponentAnnotation(type.getAnnotations())) {
errors.withSource(type).scopeAnnotationOnAbstractType(scopeAnnotation, type, source);
}
}
/**
* Gets a key for the given type, member and annotations.
*/
public static Key<?> getKey(TypeLiteral<?> type, Member member, Annotation[] annotations,
Errors errors) throws ErrorsException {
int numErrorsBefore = errors.size();
Annotation found = findBindingAnnotation(errors, member, annotations);
errors.throwIfNewErrors(numErrorsBefore);
return found == null ? Key.get(type) : Key.get(type, found);
}
/**
* Returns the binding annotation on {@code member}, or null if there isn't one.
*/
public static Annotation findBindingAnnotation(
Errors errors, Member member, Annotation[] annotations) {
Annotation found = null;
for (Annotation annotation : annotations) {
Class<? extends Annotation> annotationType = annotation.annotationType();
if (isBindingAnnotation(annotationType)) {
if (found != null) {
errors.duplicateBindingAnnotations(member, found.annotationType(), annotationType);
} else {
found = annotation;
}
}
}
return found;
}
/**
* Returns true if annotations of the specified type are binding annotations.
*/
public static boolean isBindingAnnotation(Class<? extends Annotation> annotationType) {
return bindingAnnotationChecker.hasAnnotations(annotationType);
}
/**
* If the annotation is an instance of {@code javax.inject.Named}, canonicalizes to
* com.google.guice.name.Named. Returns the given annotation otherwise.
*/
public static Annotation canonicalizeIfNamed(Annotation annotation) {
if (annotation instanceof javax.inject.Named) {
return Names.named(((javax.inject.Named) annotation).value());
} else {
return annotation;
}
}
/**
* If the annotation is the class {@code javax.inject.Named}, canonicalizes to
* com.google.guice.name.Named. Returns the given annotation class otherwise.
*/
public static Class<? extends Annotation> canonicalizeIfNamed(
Class<? extends Annotation> annotationType) {
if (annotationType == javax.inject.Named.class) {
return Named.class;
} else {
return annotationType;
}
}
/**
* Checks for the presence of annotations. Caches results because Android doesn't.
*/
static class AnnotationChecker {
private final Collection<Class<? extends Annotation>> annotationTypes;
/**
* Returns true if the given class has one of the desired annotations.
*/
private CacheLoader<Class<? extends Annotation>, Boolean> hasAnnotations =
new CacheLoader<Class<? extends Annotation>, Boolean>() {
public Boolean load(Class<? extends Annotation> annotationType) {
for (Annotation annotation : annotationType.getAnnotations()) {
if (annotationTypes.contains(annotation.annotationType())) {
return true;
}
}
return false;
}
};
final LoadingCache<Class<? extends Annotation>, Boolean> cache = CacheBuilder.newBuilder().weakKeys()
.build(hasAnnotations);
/**
* Constructs a new checker that looks for annotations of the given types.
*/
AnnotationChecker(Collection<Class<? extends Annotation>> annotationTypes) {
this.annotationTypes = annotationTypes;
}
/**
* Returns true if the given type has one of the desired annotations.
*/
boolean hasAnnotations(Class<? extends Annotation> annotated) {
return cache.getUnchecked(annotated);
}
}
}

View file

@ -0,0 +1,167 @@
package com.google.inject.internal;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Binder;
import com.google.inject.ConfigurationException;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
import com.google.inject.binder.AnnotatedBindingBuilder;
import com.google.inject.binder.ScopedBindingBuilder;
import com.google.inject.spi.Element;
import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.Message;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.util.List;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Bind a non-constant key.
*/
public class BindingBuilder<T> extends AbstractBindingBuilder<T>
implements AnnotatedBindingBuilder<T> {
public BindingBuilder(Binder binder, List<Element> elements, Object source, Key<T> key) {
super(binder, elements, source, key);
}
public BindingBuilder<T> annotatedWith(Class<? extends Annotation> annotationType) {
annotatedWithInternal(annotationType);
return this;
}
public BindingBuilder<T> annotatedWith(Annotation annotation) {
annotatedWithInternal(annotation);
return this;
}
public BindingBuilder<T> to(Class<? extends T> implementation) {
return to(Key.get(implementation));
}
public BindingBuilder<T> to(TypeLiteral<? extends T> implementation) {
return to(Key.get(implementation));
}
public BindingBuilder<T> to(Key<? extends T> linkedKey) {
checkNotNull(linkedKey, "linkedKey");
checkNotTargetted();
BindingImpl<T> base = getBinding();
setBinding(new LinkedBindingImpl<T>(
base.getSource(), base.getKey(), base.getScoping(), linkedKey));
return this;
}
public void toInstance(T instance) {
checkNotTargetted();
// lookup the injection points, adding any errors to the binder's errors list
Set<InjectionPoint> injectionPoints;
if (instance != null) {
try {
injectionPoints = InjectionPoint.forInstanceMethodsAndFields(instance.getClass());
} catch (ConfigurationException e) {
copyErrorsToBinder(e);
injectionPoints = e.getPartialValue();
}
} else {
binder.addError(BINDING_TO_NULL);
injectionPoints = ImmutableSet.of();
}
BindingImpl<T> base = getBinding();
setBinding(new InstanceBindingImpl<T>(
base.getSource(), base.getKey(), Scoping.EAGER_SINGLETON, injectionPoints, instance));
}
@SuppressWarnings("unchecked")
public BindingBuilder<T> toProvider(Provider<? extends T> provider) {
return toProvider((javax.inject.Provider<T>) provider);
}
public BindingBuilder<T> toProvider(javax.inject.Provider<? extends T> provider) {
checkNotNull(provider, "provider");
checkNotTargetted();
// lookup the injection points, adding any errors to the binder's errors list
Set<InjectionPoint> injectionPoints;
try {
injectionPoints = InjectionPoint.forInstanceMethodsAndFields(provider.getClass());
} catch (ConfigurationException e) {
copyErrorsToBinder(e);
injectionPoints = e.getPartialValue();
}
BindingImpl<T> base = getBinding();
setBinding(new ProviderInstanceBindingImpl<T>(
base.getSource(), base.getKey(), base.getScoping(), injectionPoints, provider));
return this;
}
public BindingBuilder<T> toProvider(
Class<? extends javax.inject.Provider<? extends T>> providerType) {
return toProvider(Key.get(providerType));
}
public BindingBuilder<T> toProvider(
TypeLiteral<? extends javax.inject.Provider<? extends T>> providerType) {
return toProvider(Key.get(providerType));
}
public BindingBuilder<T> toProvider(
Key<? extends javax.inject.Provider<? extends T>> providerKey) {
checkNotNull(providerKey, "providerKey");
checkNotTargetted();
BindingImpl<T> base = getBinding();
setBinding(new LinkedProviderBindingImpl<T>(
base.getSource(), base.getKey(), base.getScoping(), providerKey));
return this;
}
public <S extends T> ScopedBindingBuilder toConstructor(Constructor<S> constructor) {
return toConstructor(constructor, TypeLiteral.get(constructor.getDeclaringClass()));
}
public <S extends T> ScopedBindingBuilder toConstructor(Constructor<S> constructor,
TypeLiteral<? extends S> type) {
checkNotNull(constructor, "constructor");
checkNotNull(type, "type");
checkNotTargetted();
BindingImpl<T> base = getBinding();
Set<InjectionPoint> injectionPoints;
try {
injectionPoints = InjectionPoint.forInstanceMethodsAndFields(type);
} catch (ConfigurationException e) {
copyErrorsToBinder(e);
injectionPoints = e.getPartialValue();
}
try {
InjectionPoint constructorPoint = InjectionPoint.forConstructor(constructor, type);
setBinding(new ConstructorBindingImpl<T>(base.getKey(), base.getSource(), base.getScoping(),
constructorPoint, injectionPoints));
} catch (ConfigurationException e) {
copyErrorsToBinder(e);
}
return this;
}
@Override
public String toString() {
return "BindingBuilder<" + getBinding().getKey().getTypeLiteral() + ">";
}
private void copyErrorsToBinder(ConfigurationException e) {
for (Message message : e.getErrorMessages()) {
binder.addError(message);
}
}
}

View file

@ -0,0 +1,100 @@
package com.google.inject.internal;
import com.google.common.base.MoreObjects;
import com.google.inject.Binding;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.spi.BindingScopingVisitor;
import com.google.inject.spi.ElementVisitor;
import com.google.inject.spi.InstanceBinding;
public abstract class BindingImpl<T> implements Binding<T> {
private final InjectorImpl injector;
private final Key<T> key;
private final Object source;
private final Scoping scoping;
private final InternalFactory<? extends T> internalFactory;
private volatile Provider<T> provider;
public BindingImpl(InjectorImpl injector, Key<T> key, Object source,
InternalFactory<? extends T> internalFactory, Scoping scoping) {
this.injector = injector;
this.key = key;
this.source = source;
this.internalFactory = internalFactory;
this.scoping = scoping;
}
protected BindingImpl(Object source, Key<T> key, Scoping scoping) {
this.internalFactory = null;
this.injector = null;
this.source = source;
this.key = key;
this.scoping = scoping;
}
public Key<T> getKey() {
return key;
}
public Object getSource() {
return source;
}
public Provider<T> getProvider() {
if (provider == null) {
if (injector == null) {
throw new UnsupportedOperationException("getProvider() not supported for module bindings");
}
provider = injector.getProvider(key);
}
return provider;
}
public InternalFactory<? extends T> getInternalFactory() {
return internalFactory;
}
public Scoping getScoping() {
return scoping;
}
/**
* Is this a constant binding? This returns true for constant bindings as
* well as toInstance() bindings.
*/
public boolean isConstant() {
return this instanceof InstanceBinding;
}
public <V> V acceptVisitor(ElementVisitor<V> visitor) {
return visitor.visit(this);
}
public <V> V acceptScopingVisitor(BindingScopingVisitor<V> visitor) {
return scoping.acceptVisitor(visitor);
}
protected BindingImpl<T> withScoping(Scoping scoping) {
throw new AssertionError();
}
protected BindingImpl<T> withKey(Key<T> key) {
throw new AssertionError();
}
@Override
public String toString() {
return MoreObjects.toStringHelper(Binding.class)
.add("key", key)
.add("scope", scoping)
.add("source", source)
.toString();
}
public InjectorImpl getInjector() {
return injector;
}
}

View file

@ -0,0 +1,180 @@
package com.google.inject.internal;
import com.google.inject.Binder;
import com.google.inject.Binding;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.spi.ConstructorBinding;
import com.google.inject.spi.ConvertedConstantBinding;
import com.google.inject.spi.ExposedBinding;
import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.InstanceBinding;
import com.google.inject.spi.LinkedKeyBinding;
import com.google.inject.spi.PrivateElements;
import com.google.inject.spi.ProviderBinding;
import com.google.inject.spi.ProviderInstanceBinding;
import com.google.inject.spi.ProviderKeyBinding;
import com.google.inject.spi.UntargettedBinding;
import java.util.Set;
/**
* Handles {@link Binder#bind} and {@link Binder#bindConstant} elements.
*/
final class BindingProcessor extends AbstractBindingProcessor {
private final Initializer initializer;
BindingProcessor(Errors errors, Initializer initializer, ProcessedBindingData bindingData) {
super(errors, bindingData);
this.initializer = initializer;
}
@Override
public <T> Boolean visit(Binding<T> command) {
Class<?> rawType = command.getKey().getTypeLiteral().getRawType();
if (Void.class.equals(rawType)) {
if (command instanceof ProviderInstanceBinding
&& ((ProviderInstanceBinding) command).getUserSuppliedProvider()
instanceof ProviderMethod) {
errors.voidProviderMethod();
} else {
errors.missingConstantValues();
}
return true;
}
if (rawType == Provider.class) {
errors.bindingToProvider();
return true;
}
return command.acceptTargetVisitor(new Processor<T, Boolean>((BindingImpl<T>) command) {
@Override
public Boolean visit(ConstructorBinding<? extends T> binding) {
prepareBinding();
try {
ConstructorBindingImpl<T> onInjector = ConstructorBindingImpl.create(injector, key,
binding.getConstructor(), source, scoping, errors, false, false);
scheduleInitialization(onInjector);
putBinding(onInjector);
} catch (ErrorsException e) {
errors.merge(e.getErrors());
putBinding(invalidBinding(injector, key, source));
}
return true;
}
@Override
public Boolean visit(InstanceBinding<? extends T> binding) {
prepareBinding();
Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
T instance = binding.getInstance();
@SuppressWarnings("unchecked") // safe to cast to binding<T> because
// the processor was constructed w/ it
Initializable<T> ref = initializer.requestInjection(
injector, instance, (Binding<T>) binding, source, injectionPoints);
ConstantFactory<? extends T> factory = new ConstantFactory<T>(ref);
InternalFactory<? extends T> scopedFactory
= Scoping.scope(key, injector, factory, source, scoping);
putBinding(new InstanceBindingImpl<T>(injector, key, source, scopedFactory, injectionPoints,
instance));
return true;
}
@Override
public Boolean visit(ProviderInstanceBinding<? extends T> binding) {
prepareBinding();
javax.inject.Provider<? extends T> provider = binding.getUserSuppliedProvider();
Set<InjectionPoint> injectionPoints = binding.getInjectionPoints();
Initializable<? extends javax.inject.Provider<? extends T>> initializable =
initializer.<javax.inject.Provider<? extends T>>requestInjection(
injector, provider, null, source, injectionPoints);
// always visited with Binding<T>
@SuppressWarnings("unchecked")
InternalFactory<T> factory = new InternalFactoryToInitializableAdapter<T>(
initializable, source,
injector.provisionListenerStore.get((ProviderInstanceBinding<T>) binding));
InternalFactory<? extends T> scopedFactory
= Scoping.scope(key, injector, factory, source, scoping);
putBinding(new ProviderInstanceBindingImpl<T>(injector, key, source, scopedFactory, scoping,
provider, injectionPoints));
return true;
}
@Override
public Boolean visit(ProviderKeyBinding<? extends T> binding) {
prepareBinding();
Key<? extends javax.inject.Provider<? extends T>> providerKey = binding.getProviderKey();
// always visited with Binding<T>
@SuppressWarnings("unchecked")
BoundProviderFactory<T> boundProviderFactory = new BoundProviderFactory<T>(
injector, providerKey, source,
injector.provisionListenerStore.get((ProviderKeyBinding<T>) binding));
bindingData.addCreationListener(boundProviderFactory);
InternalFactory<? extends T> scopedFactory = Scoping.scope(
key, injector, (InternalFactory<? extends T>) boundProviderFactory, source, scoping);
putBinding(new LinkedProviderBindingImpl<T>(
injector, key, source, scopedFactory, scoping, providerKey));
return true;
}
@Override
public Boolean visit(LinkedKeyBinding<? extends T> binding) {
prepareBinding();
Key<? extends T> linkedKey = binding.getLinkedKey();
if (key.equals(linkedKey)) {
errors.recursiveBinding();
}
FactoryProxy<T> factory = new FactoryProxy<T>(injector, key, linkedKey, source);
bindingData.addCreationListener(factory);
InternalFactory<? extends T> scopedFactory
= Scoping.scope(key, injector, factory, source, scoping);
putBinding(
new LinkedBindingImpl<T>(injector, key, source, scopedFactory, scoping, linkedKey));
return true;
}
@Override
public Boolean visit(UntargettedBinding<? extends T> untargetted) {
return false;
}
@Override
public Boolean visit(ExposedBinding<? extends T> binding) {
throw new IllegalArgumentException("Cannot apply a non-module element");
}
@Override
public Boolean visit(ConvertedConstantBinding<? extends T> binding) {
throw new IllegalArgumentException("Cannot apply a non-module element");
}
@Override
public Boolean visit(ProviderBinding<? extends T> binding) {
throw new IllegalArgumentException("Cannot apply a non-module element");
}
@Override
protected Boolean visitOther(Binding<? extends T> binding) {
throw new IllegalStateException("BindingProcessor should override all visitations");
}
});
}
@Override
public Boolean visit(PrivateElements privateElements) {
for (Key<?> key : privateElements.getExposedKeys()) {
bindExposed(privateElements, key);
}
return false; // leave the private elements for the PrivateElementsProcessor to handle
}
private <T> void bindExposed(PrivateElements privateElements, Key<T> key) {
ExposedKeyFactory<T> exposedKeyFactory = new ExposedKeyFactory<T>(key, privateElements);
bindingData.addCreationListener(exposedKeyFactory);
putBinding(new ExposedBindingImpl<T>(
injector, privateElements.getExposedSource(key), key, exposedKeyFactory, privateElements));
}
}

View file

@ -0,0 +1,66 @@
package com.google.inject.internal;
import com.google.inject.Key;
import com.google.inject.internal.InjectorImpl.JitLimitation;
import com.google.inject.spi.Dependency;
import javax.inject.Provider;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Delegates to a custom factory which is also bound in the injector.
*/
final class BoundProviderFactory<T> extends ProviderInternalFactory<T> implements CreationListener {
final Key<? extends javax.inject.Provider<? extends T>> providerKey;
private final ProvisionListenerStackCallback<T> provisionCallback;
private final InjectorImpl injector;
private InternalFactory<? extends javax.inject.Provider<? extends T>> providerFactory;
BoundProviderFactory(
InjectorImpl injector,
Key<? extends javax.inject.Provider<? extends T>> providerKey,
Object source,
ProvisionListenerStackCallback<T> provisionCallback) {
super(source);
this.provisionCallback = checkNotNull(provisionCallback, "provisionCallback");
this.injector = injector;
this.providerKey = providerKey;
}
public void notify(Errors errors) {
try {
providerFactory = injector.getInternalFactory(providerKey, errors.withSource(source), JitLimitation.NEW_OR_EXISTING_JIT);
} catch (ErrorsException e) {
errors.merge(e.getErrors());
}
}
public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
throws ErrorsException {
context.pushState(providerKey, source);
try {
errors = errors.withSource(providerKey);
javax.inject.Provider<? extends T> provider = providerFactory.get(errors, context, dependency, true);
return circularGet(provider, errors, context, dependency, provisionCallback);
} finally {
context.popState();
}
}
@Override
protected T provision(Provider<? extends T> provider, Errors errors, Dependency<?> dependency,
ConstructionContext<T> constructionContext) throws ErrorsException {
try {
return super.provision(provider, errors, dependency, constructionContext);
} catch (RuntimeException userException) {
throw errors.errorInProvider(userException).toException();
}
}
@Override
public String toString() {
return providerKey.toString();
}
}

View file

@ -0,0 +1,5 @@
package com.google.inject.internal;
public interface CircularDependencyProxy {
// marker interface
}

View file

@ -0,0 +1,115 @@
package com.google.inject.internal;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Binder;
import com.google.inject.Key;
import com.google.inject.binder.AnnotatedConstantBindingBuilder;
import com.google.inject.binder.ConstantBindingBuilder;
import com.google.inject.spi.Element;
import com.google.inject.spi.InjectionPoint;
import java.lang.annotation.Annotation;
import java.util.List;
/**
* Bind a constant.
*
*/
public final class ConstantBindingBuilderImpl<T>
extends AbstractBindingBuilder<T>
implements AnnotatedConstantBindingBuilder, ConstantBindingBuilder {
@SuppressWarnings("unchecked") // constant bindings start out with T unknown
public ConstantBindingBuilderImpl(Binder binder, List<Element> elements, Object source) {
super(binder, elements, source, (Key<T>) NULL_KEY);
}
public ConstantBindingBuilder annotatedWith(Class<? extends Annotation> annotationType) {
annotatedWithInternal(annotationType);
return this;
}
public ConstantBindingBuilder annotatedWith(Annotation annotation) {
annotatedWithInternal(annotation);
return this;
}
public void to(final String value) {
toConstant(String.class, value);
}
public void to(final int value) {
toConstant(Integer.class, value);
}
public void to(final long value) {
toConstant(Long.class, value);
}
public void to(final boolean value) {
toConstant(Boolean.class, value);
}
public void to(final double value) {
toConstant(Double.class, value);
}
public void to(final float value) {
toConstant(Float.class, value);
}
public void to(final short value) {
toConstant(Short.class, value);
}
public void to(final char value) {
toConstant(Character.class, value);
}
public void to(final byte value) {
toConstant(Byte.class, value);
}
public void to(final Class<?> value) {
toConstant(Class.class, value);
}
public <E extends Enum<E>> void to(final E value) {
toConstant(value.getDeclaringClass(), value);
}
private void toConstant(Class<?> type, Object instance) {
// this type will define T, so these assignments are safe
@SuppressWarnings("unchecked")
Class<T> typeAsClassT = (Class<T>) type;
@SuppressWarnings("unchecked")
T instanceAsT = (T) instance;
if (keyTypeIsSet()) {
binder.addError(CONSTANT_VALUE_ALREADY_SET);
return;
}
BindingImpl<T> base = getBinding();
Key<T> key;
if (base.getKey().getAnnotation() != null) {
key = Key.get(typeAsClassT, base.getKey().getAnnotation());
} else if (base.getKey().getAnnotationType() != null) {
key = Key.get(typeAsClassT, base.getKey().getAnnotationType());
} else {
key = Key.get(typeAsClassT);
}
if (instanceAsT == null) {
binder.addError(BINDING_TO_NULL);
}
setBinding(new InstanceBindingImpl<T>(
base.getSource(), key, base.getScoping(), ImmutableSet.<InjectionPoint>of(), instanceAsT));
}
@Override
public String toString() {
return "ConstantBindingBuilder";
}
}

View file

@ -0,0 +1,24 @@
package com.google.inject.internal;
import com.google.common.base.MoreObjects;
import com.google.inject.spi.Dependency;
final class ConstantFactory<T> implements InternalFactory<T> {
private final Initializable<T> initializable;
public ConstantFactory(Initializable<T> initializable) {
this.initializable = initializable;
}
public T get(Errors errors, InternalContext context, Dependency dependency, boolean linked)
throws ErrorsException {
return initializable.get(errors);
}
public String toString() {
return MoreObjects.toStringHelper(ConstantFactory.class)
.add("value", initializable)
.toString();
}
}

View file

@ -0,0 +1,75 @@
package com.google.inject.internal;
import com.google.inject.internal.InjectorImpl.InjectorOptions;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.List;
/**
* Context of a dependency construction. Used to manage circular references.
*/
final class ConstructionContext<T> {
T currentReference;
boolean constructing;
List<DelegatingInvocationHandler<T>> invocationHandlers;
public T getCurrentReference() {
return currentReference;
}
public void setCurrentReference(T currentReference) {
this.currentReference = currentReference;
}
public void removeCurrentReference() {
this.currentReference = null;
}
public boolean isConstructing() {
return constructing;
}
public void startConstruction() {
this.constructing = true;
}
public void finishConstruction() {
this.constructing = false;
invocationHandlers = null;
}
public Object createProxy(Errors errors, InjectorOptions injectorOptions,
Class<?> expectedType) throws ErrorsException {
if (injectorOptions.disableCircularProxies) {
throw errors.circularProxiesDisabled(expectedType).toException();
}
if (!expectedType.isInterface()) {
throw errors.cannotSatisfyCircularDependency(expectedType).toException();
}
if (invocationHandlers == null) {
invocationHandlers = new ArrayList<DelegatingInvocationHandler<T>>();
}
DelegatingInvocationHandler<T> invocationHandler = new DelegatingInvocationHandler<T>();
invocationHandlers.add(invocationHandler);
ClassLoader classLoader = expectedType.getClass().getClassLoader() != null ?
expectedType.getClass().getClassLoader() : ClassLoader.getSystemClassLoader();
return expectedType.cast(Proxy.newProxyInstance(classLoader,
new Class[]{expectedType, CircularDependencyProxy.class}, invocationHandler));
}
public void setProxyDelegates(T delegate) {
if (invocationHandlers != null) {
for (DelegatingInvocationHandler<T> handler : invocationHandlers) {
handler.setDelegate(delegate);
}
// initialization of each handler can happen no more than once
invocationHandlers = null;
}
}
}

View file

@ -0,0 +1,30 @@
package com.google.inject.internal;
import com.google.inject.spi.InjectionPoint;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
/**
* Proxies calls to a {@link java.lang.reflect.Constructor} for a class
* {@code T}.
*/
interface ConstructionProxy<T> {
/**
* Constructs an instance of {@code T} for the given arguments.
*/
T newInstance(Object... arguments) throws InvocationTargetException;
/**
* Returns the injection point for this constructor.
*/
InjectionPoint getInjectionPoint();
/**
* Returns the injected constructor. If the injected constructor is synthetic (such as generated
* code for method interception), the natural constructor is returned.
*/
Constructor<T> getConstructor();
}

View file

@ -0,0 +1,12 @@
package com.google.inject.internal;
/**
* Creates {@link ConstructionProxy} instances.
*/
interface ConstructionProxyFactory<T> {
/**
* Gets a construction proxy for the given constructor.
*/
ConstructionProxy<T> create() throws ErrorsException;
}

View file

@ -0,0 +1,258 @@
package com.google.inject.internal;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Binder;
import com.google.inject.ConfigurationException;
import com.google.inject.Inject;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
import com.google.inject.internal.util.Classes;
import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.ConstructorBinding;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.InjectionPoint;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Modifier;
import java.util.Set;
import static com.google.common.base.Preconditions.checkState;
import static com.google.inject.internal.Annotations.findScopeAnnotation;
final class ConstructorBindingImpl<T> extends BindingImpl<T>
implements ConstructorBinding<T>, DelayedInitialize {
private final Factory<T> factory;
private final InjectionPoint constructorInjectionPoint;
private ConstructorBindingImpl(InjectorImpl injector, Key<T> key, Object source,
InternalFactory<? extends T> scopedFactory, Scoping scoping, Factory<T> factory,
InjectionPoint constructorInjectionPoint) {
super(injector, key, source, scopedFactory, scoping);
this.factory = factory;
this.constructorInjectionPoint = constructorInjectionPoint;
}
public ConstructorBindingImpl(Key<T> key, Object source, Scoping scoping,
InjectionPoint constructorInjectionPoint, Set<InjectionPoint> injectionPoints) {
super(source, key, scoping);
this.factory = new Factory<T>(false, key);
ConstructionProxy<T> constructionProxy
= new DefaultConstructionProxyFactory<T>(constructorInjectionPoint).create();
this.constructorInjectionPoint = constructorInjectionPoint;
factory.constructorInjector = new ConstructorInjector<T>(
injectionPoints, constructionProxy, null, null);
}
/**
* @param constructorInjector the constructor to use, or {@code null} to use the default.
* @param failIfNotLinked true if this ConstructorBindingImpl's InternalFactory should
* only succeed if retrieved from a linked binding
*/
static <T> ConstructorBindingImpl<T> create(InjectorImpl injector, Key<T> key,
InjectionPoint constructorInjector, Object source, Scoping scoping, Errors errors,
boolean failIfNotLinked, boolean failIfNotExplicit)
throws ErrorsException {
int numErrors = errors.size();
@SuppressWarnings("unchecked") // constructorBinding guarantees type is consistent
Class<? super T> rawType = constructorInjector == null
? key.getTypeLiteral().getRawType()
: (Class) constructorInjector.getDeclaringType().getRawType();
// We can't inject abstract classes.
if (Modifier.isAbstract(rawType.getModifiers())) {
errors.missingImplementation(key);
}
// Error: Inner class.
if (Classes.isInnerClass(rawType)) {
errors.cannotInjectInnerClass(rawType);
}
errors.throwIfNewErrors(numErrors);
// Find a constructor annotated @Inject
if (constructorInjector == null) {
try {
constructorInjector = InjectionPoint.forConstructorOf(key.getTypeLiteral());
if (failIfNotExplicit && !hasAtInject((Constructor) constructorInjector.getMember())) {
errors.atInjectRequired(rawType);
}
} catch (ConfigurationException e) {
throw errors.merge(e.getErrorMessages()).toException();
}
}
// if no scope is specified, look for a scoping annotation on the concrete class
if (!scoping.isExplicitlyScoped()) {
Class<?> annotatedType = constructorInjector.getMember().getDeclaringClass();
Class<? extends Annotation> scopeAnnotation = findScopeAnnotation(errors, annotatedType);
if (scopeAnnotation != null) {
scoping = Scoping.makeInjectable(Scoping.forAnnotation(scopeAnnotation),
injector, errors.withSource(rawType));
}
}
errors.throwIfNewErrors(numErrors);
Factory<T> factoryFactory = new Factory<T>(failIfNotLinked, key);
InternalFactory<? extends T> scopedFactory
= Scoping.scope(key, injector, factoryFactory, source, scoping);
return new ConstructorBindingImpl<T>(
injector, key, source, scopedFactory, scoping, factoryFactory, constructorInjector);
}
/**
* Returns true if the inject annotation is on the constructor.
*/
private static boolean hasAtInject(Constructor cxtor) {
return cxtor.isAnnotationPresent(Inject.class)
|| cxtor.isAnnotationPresent(javax.inject.Inject.class);
}
@SuppressWarnings("unchecked") // the result type always agrees with the ConstructorInjector type
public void initialize(InjectorImpl injector, Errors errors) throws ErrorsException {
factory.constructorInjector =
(ConstructorInjector<T>) injector.constructors.get(constructorInjectionPoint, errors);
factory.provisionCallback =
injector.provisionListenerStore.get(this);
}
/**
* True if this binding has been initialized and is ready for use.
*/
boolean isInitialized() {
return factory.constructorInjector != null;
}
/**
* Returns an injection point that can be used to clean up the constructor store.
*/
InjectionPoint getInternalConstructor() {
if (factory.constructorInjector != null) {
return factory.constructorInjector.getConstructionProxy().getInjectionPoint();
} else {
return constructorInjectionPoint;
}
}
/**
* Returns a set of dependencies that can be iterated over to clean up stray JIT bindings.
*/
Set<Dependency<?>> getInternalDependencies() {
ImmutableSet.Builder<InjectionPoint> builder = ImmutableSet.builder();
if (factory.constructorInjector == null) {
builder.add(constructorInjectionPoint);
// If the below throws, it's OK -- we just ignore those dependencies, because no one
// could have used them anyway.
try {
builder.addAll(InjectionPoint.forInstanceMethodsAndFields(constructorInjectionPoint.getDeclaringType()));
} catch (ConfigurationException ignored) {
}
} else {
builder.add(getConstructor())
.addAll(getInjectableMembers());
}
return Dependency.forInjectionPoints(builder.build());
}
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
checkState(factory.constructorInjector != null, "not initialized");
return visitor.visit(this);
}
public InjectionPoint getConstructor() {
checkState(factory.constructorInjector != null, "Binding is not ready");
return factory.constructorInjector.getConstructionProxy().getInjectionPoint();
}
public Set<InjectionPoint> getInjectableMembers() {
checkState(factory.constructorInjector != null, "Binding is not ready");
return factory.constructorInjector.getInjectableMembers();
}
public Set<Dependency<?>> getDependencies() {
return Dependency.forInjectionPoints(new ImmutableSet.Builder<InjectionPoint>()
.add(getConstructor())
.addAll(getInjectableMembers())
.build());
}
@Override
protected BindingImpl<T> withScoping(Scoping scoping) {
return new ConstructorBindingImpl<T>(
null, getKey(), getSource(), factory, scoping, factory, constructorInjectionPoint);
}
@Override
protected BindingImpl<T> withKey(Key<T> key) {
return new ConstructorBindingImpl<T>(
null, key, getSource(), factory, getScoping(), factory, constructorInjectionPoint);
}
@SuppressWarnings("unchecked") // the raw constructor member and declaring type always agree
public void applyTo(Binder binder) {
InjectionPoint constructor = getConstructor();
getScoping().applyTo(binder.withSource(getSource()).bind(getKey()).toConstructor(
(Constructor) getConstructor().getMember(), (TypeLiteral) constructor.getDeclaringType()));
}
@Override
public String toString() {
return MoreObjects.toStringHelper(ConstructorBinding.class)
.add("key", getKey())
.add("source", getSource())
.add("scope", getScoping())
.toString();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof ConstructorBindingImpl) {
ConstructorBindingImpl<?> o = (ConstructorBindingImpl<?>) obj;
return getKey().equals(o.getKey())
&& getScoping().equals(o.getScoping())
&& Objects.equal(constructorInjectionPoint, o.constructorInjectionPoint);
} else {
return false;
}
}
@Override
public int hashCode() {
return Objects.hashCode(getKey(), getScoping(), constructorInjectionPoint);
}
private static class Factory<T> implements InternalFactory<T> {
private final boolean failIfNotLinked;
private final Key<?> key;
private ConstructorInjector<T> constructorInjector;
private ProvisionListenerStackCallback<T> provisionCallback;
Factory(boolean failIfNotLinked, Key<?> key) {
this.failIfNotLinked = failIfNotLinked;
this.key = key;
}
@SuppressWarnings("unchecked")
public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
throws ErrorsException {
checkState(constructorInjector != null, "Constructor not ready");
if (failIfNotLinked && !linked) {
throw errors.jitDisabled(key).toException();
}
// This may not actually be safe because it could return a super type of T (if that's all the
// client needs), but it should be OK in practice thanks to the wonders of erasure.
return (T) constructorInjector.construct(errors, context,
dependency.getKey().getTypeLiteral().getRawType(), provisionCallback);
}
}
}

View file

@ -0,0 +1,112 @@
package com.google.inject.internal;
import com.google.common.collect.ImmutableSet;
import com.google.inject.internal.ProvisionListenerStackCallback.ProvisionCallback;
import com.google.inject.spi.InjectionPoint;
import java.lang.reflect.InvocationTargetException;
import java.util.Set;
/**
* Creates instances using an injectable constructor. After construction, all injectable fields and
* methods are injected.
*/
final class ConstructorInjector<T> {
private final ImmutableSet<InjectionPoint> injectableMembers;
private final SingleParameterInjector<?>[] parameterInjectors;
private final ConstructionProxy<T> constructionProxy;
private final MembersInjectorImpl<T> membersInjector;
ConstructorInjector(Set<InjectionPoint> injectableMembers,
ConstructionProxy<T> constructionProxy,
SingleParameterInjector<?>[] parameterInjectors,
MembersInjectorImpl<T> membersInjector) {
this.injectableMembers = ImmutableSet.copyOf(injectableMembers);
this.constructionProxy = constructionProxy;
this.parameterInjectors = parameterInjectors;
this.membersInjector = membersInjector;
}
public ImmutableSet<InjectionPoint> getInjectableMembers() {
return injectableMembers;
}
ConstructionProxy<T> getConstructionProxy() {
return constructionProxy;
}
/**
* Construct an instance. Returns {@code Object} instead of {@code T} because
* it may return a proxy.
*/
Object construct(final Errors errors, final InternalContext context,
Class<?> expectedType,
ProvisionListenerStackCallback<T> provisionCallback)
throws ErrorsException {
final ConstructionContext<T> constructionContext = context.getConstructionContext(this);
// We have a circular reference between constructors. Return a proxy.
if (constructionContext.isConstructing()) {
// TODO (crazybob): if we can't proxy this object, can we proxy the other object?
return constructionContext.createProxy(
errors, context.getInjectorOptions(), expectedType);
}
// If we're re-entering this factory while injecting fields or methods,
// return the same instance. This prevents infinite loops.
T t = constructionContext.getCurrentReference();
if (t != null) {
return t;
}
constructionContext.startConstruction();
try {
// Optimization: Don't go through the callback stack if we have no listeners.
if (!provisionCallback.hasListeners()) {
return provision(errors, context, constructionContext);
} else {
return provisionCallback.provision(errors, context, new ProvisionCallback<T>() {
public T call() throws ErrorsException {
return provision(errors, context, constructionContext);
}
});
}
} finally {
constructionContext.finishConstruction();
}
}
/**
* Provisions a new T.
*/
private T provision(Errors errors, InternalContext context,
ConstructionContext<T> constructionContext) throws ErrorsException {
try {
T t;
try {
Object[] parameters = SingleParameterInjector.getAll(errors, context, parameterInjectors);
t = constructionProxy.newInstance(parameters);
constructionContext.setProxyDelegates(t);
} finally {
constructionContext.finishConstruction();
}
// Store reference. If an injector re-enters this factory, they'll get the same reference.
constructionContext.setCurrentReference(t);
membersInjector.injectMembers(t, errors, context, false);
membersInjector.notifyListeners(t, errors);
return t;
} catch (InvocationTargetException userException) {
Throwable cause = userException.getCause() != null
? userException.getCause()
: userException;
throw errors.withSource(constructionProxy.getInjectionPoint())
.errorInjectingConstructor(cause).toException();
} finally {
constructionContext.removeCurrentReference();
}
}
}

View file

@ -0,0 +1,63 @@
package com.google.inject.internal;
import com.google.inject.spi.InjectionPoint;
/**
* Constructor injectors by type.
*/
final class ConstructorInjectorStore {
private final InjectorImpl injector;
private final FailableCache<InjectionPoint, ConstructorInjector<?>> cache
= new FailableCache<InjectionPoint, ConstructorInjector<?>>() {
@Override
protected ConstructorInjector<?> create(InjectionPoint constructorInjector, Errors errors)
throws ErrorsException {
return createConstructor(constructorInjector, errors);
}
};
ConstructorInjectorStore(InjectorImpl injector) {
this.injector = injector;
}
/**
* Returns a new complete constructor injector with injection listeners registered.
*/
public ConstructorInjector<?> get(InjectionPoint constructorInjector, Errors errors)
throws ErrorsException {
return cache.get(constructorInjector, errors);
}
/**
* Purges an injection point from the cache. Use this only if the cache is not actually valid and
* needs to be purged. (See issue 319 and
* ImplicitBindingTest#testCircularJitBindingsLeaveNoResidue and
* #testInstancesRequestingProvidersForThemselvesWithChildInjectors for examples of when this is
* necessary.)
*
* Returns true if the injector for that point was stored in the cache, false otherwise.
*/
boolean remove(InjectionPoint ip) {
return cache.remove(ip);
}
private <T> ConstructorInjector<T> createConstructor(InjectionPoint injectionPoint, Errors errors)
throws ErrorsException {
int numErrorsBefore = errors.size();
SingleParameterInjector<?>[] constructorParameterInjectors
= injector.getParametersInjectors(injectionPoint.getDependencies(), errors);
@SuppressWarnings("unchecked") // the injector type agrees with the injection point type
MembersInjectorImpl<T> membersInjector = (MembersInjectorImpl<T>) injector.membersInjectorStore
.get(injectionPoint.getDeclaringType(), errors);
ConstructionProxyFactory<T> factory = new DefaultConstructionProxyFactory<T>(injectionPoint);
errors.throwIfNewErrors(numErrorsBefore);
return new ConstructorInjector<T>(membersInjector.getInjectionPoints(), factory.create(),
constructorParameterInjectors, membersInjector);
}
}

View file

@ -0,0 +1,5 @@
package com.google.inject.internal;
interface ContextualCallable<T> {
T call(InternalContext context) throws ErrorsException;
}

View file

@ -0,0 +1,12 @@
package com.google.inject.internal;
/**
* Something that is notified upon creation.
*/
interface CreationListener {
/**
* Notifies that creation should happen.
*/
void notify(Errors errors);
}

View file

@ -0,0 +1,308 @@
package com.google.inject.internal;
import com.google.common.base.Preconditions;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableListMultimap;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.ListMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Multimaps;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* Simplified version of {@link Lock} that is special due to how it handles deadlocks detection.
*
* <p>Is an inherent part of {@link SingletonScope}, moved into a upper level class due
* to its size and complexity.
*
* @param <ID> Lock identification provided by the client, is returned unmodified to the client
* when lock cycle is detected to identify it. Only toString() needs to be implemented.
* Lock references this object internally,
* for the purposes of Garbage Collection you should not use heavy IDs.
* Lock is referenced by a lock factory as long as it's owned by a thread.
*/
interface CycleDetectingLock<ID> {
/**
* Takes a lock in a blocking fashion in case no potential deadlocks are detected.
* If the lock was successfully owned, returns an empty map indicating no detected potential
* deadlocks.
*
* Otherwise, a map indicating threads involved in a potential deadlock are returned.
* Map is ordered by dependency cycle and lists locks for each thread that are part of
* the loop in order. Returned map is created atomically.
*
* In case no cycle is detected performance is O(threads creating singletons),
* in case cycle is detected performance is O(singleton locks).
*/
ListMultimap<Long, ID> lockOrDetectPotentialLocksCycle();
/**
* Unlocks previously locked lock.
*/
void unlock();
/**
* Wraps locks so they would never cause a deadlock. On each
* {@link CycleDetectingLock#lockOrDetectPotentialLocksCycle} we check for dependency cycles
* within locks created by the same factory. Either we detect a cycle and return it
* or take it atomically.
*
* <p>Important to note that we do not prevent deadlocks in the client code. As an example:
* Thread A takes lock L and creates singleton class CA depending on the singleton class CB.
* Meanwhile thread B is creating class CB and is waiting on the lock L. Issue happens
* due to client code creating interdependent classes and using locks, where
* no guarantees on the creation order from Guice are provided.
*
* <p>Instances of these locks are not intended to be exposed outside of {@link SingletonScope}.
*/
class CycleDetectingLockFactory<ID> {
/**
* Lists locks that thread owns.
* Used only to populate locks in a potential cycle when it is detected.
*
* Key: thread id
* Value: stack of locks that were owned.
*
* Element is added inside {@link #lockOrDetectPotentialLocksCycle()} after {@link Lock#lock}
* is called. Element is removed inside {@link #unlock()} synchronously with
* {@link Lock#unlock()} call.
*
* Same lock can only be present several times for the same thread as locks are
* reentrant. Lock can not be owned by several different threads as the same time.
*
* Guarded by {@code this}.
*/
private final Multimap<Long, ReentrantCycleDetectingLock> locksOwnedByThread =
LinkedHashMultimap.create();
/**
* Specifies lock that thread is currently waiting on to own it.
* Used only for purposes of locks cycle detection.
*
* Key: thread id
* Value: lock that is being waited on
*
* Element is added inside {@link #lockOrDetectPotentialLocksCycle()} before {@link Lock#lock}
* is called. Element is removed inside {@link #lockOrDetectPotentialLocksCycle()} after
* {@link Lock#lock} and synchronously with adding it to {@link #locksOwnedByThread}.
*
* Same lock can be added for several threads in case all of them are trying to
* take it.
*
* Guarded by {@code this}.
*/
private Map<Long, ReentrantCycleDetectingLock> lockThreadIsWaitingOn = Maps.newHashMap();
/**
* Creates new lock within this factory context. We can guarantee that locks created by
* the same factory would not deadlock.
*
* @param newLockId lock id that would be used to report lock cycles if detected
*/
CycleDetectingLock<ID> create(ID newLockId) {
return new ReentrantCycleDetectingLock(newLockId, new ReentrantLock());
}
/**
* The implementation for {@link CycleDetectingLock}.
*/
class ReentrantCycleDetectingLock implements CycleDetectingLock<ID> {
/**
* Underlying lock used for actual waiting when no potential deadlocks are detected.
*/
private final Lock lockImplementation;
/**
* User id for this lock.
*/
private final ID userLockId;
/**
* Thread id for the thread that owned this lock. Nullable.
* Guarded by {@code CycleDetectingLockFactory.this}.
*/
private Long lockOwnerThreadId = null;
/**
* Number of times that thread owned this lock.
* Guarded by {@code CycleDetectingLockFactory.this}.
*/
private int lockReentranceCount = 0;
ReentrantCycleDetectingLock(ID userLockId, Lock lockImplementation) {
this.userLockId = Preconditions.checkNotNull(userLockId, "userLockId");
this.lockImplementation = Preconditions.checkNotNull(
lockImplementation, "lockImplementation");
}
@Override
public ListMultimap<Long, ID> lockOrDetectPotentialLocksCycle() {
final long currentThreadId = Thread.currentThread().getId();
synchronized (CycleDetectingLockFactory.this) {
checkState();
ListMultimap<Long, ID> locksInCycle = detectPotentialLocksCycle();
if (!locksInCycle.isEmpty()) {
// potential deadlock is found, we don't try to take this lock
return locksInCycle;
}
lockThreadIsWaitingOn.put(currentThreadId, this);
}
// this may be blocking, but we don't expect it to cause a deadlock
lockImplementation.lock();
synchronized (CycleDetectingLockFactory.this) {
// current thread is no longer waiting on this lock
lockThreadIsWaitingOn.remove(currentThreadId);
checkState();
// mark it as owned by us
lockOwnerThreadId = currentThreadId;
lockReentranceCount++;
// add this lock to the list of locks owned by a current thread
locksOwnedByThread.put(currentThreadId, this);
}
// no deadlock is found, locking successful
return ImmutableListMultimap.of();
}
@Override
public void unlock() {
final long currentThreadId = Thread.currentThread().getId();
synchronized (CycleDetectingLockFactory.this) {
checkState();
Preconditions.checkState(lockOwnerThreadId != null,
"Thread is trying to unlock a lock that is not locked");
Preconditions.checkState(lockOwnerThreadId == currentThreadId,
"Thread is trying to unlock a lock owned by another thread");
// releasing underlying lock
lockImplementation.unlock();
// be sure to release the lock synchronously with updating internal state
lockReentranceCount--;
if (lockReentranceCount == 0) {
// we no longer own this lock
lockOwnerThreadId = null;
Preconditions.checkState(locksOwnedByThread.remove(currentThreadId, this),
"Internal error: Can not find this lock in locks owned by a current thread");
if (locksOwnedByThread.get(currentThreadId).isEmpty()) {
// clearing memory
locksOwnedByThread.removeAll(currentThreadId);
}
}
}
}
/**
* Check consistency of an internal state.
*/
void checkState() throws IllegalStateException {
final long currentThreadId = Thread.currentThread().getId();
Preconditions.checkState(!lockThreadIsWaitingOn.containsKey(currentThreadId),
"Internal error: Thread should not be in a waiting thread on a lock now");
if (lockOwnerThreadId != null) {
// check state of a locked lock
Preconditions.checkState(lockReentranceCount >= 0,
"Internal error: Lock ownership and reentrance count internal states do not match");
Preconditions.checkState(locksOwnedByThread.get(lockOwnerThreadId).contains(this),
"Internal error: Set of locks owned by a current thread and lock "
+ "ownership status do not match");
} else {
// check state of a non locked lock
Preconditions.checkState(lockReentranceCount == 0,
"Internal error: Reentrance count of a non locked lock is expect to be zero");
Preconditions.checkState(!locksOwnedByThread.values().contains(this),
"Internal error: Non locked lock should not be owned by any thread");
}
}
/**
* Algorithm to detect a potential lock cycle.
*
* For lock's thread owner check which lock is it trying to take.
* Repeat recursively. When current thread is found a potential cycle is detected.
*
* @see CycleDetectingLock#lockOrDetectPotentialLocksCycle()
*/
private ListMultimap<Long, ID> detectPotentialLocksCycle() {
final long currentThreadId = Thread.currentThread().getId();
if (lockOwnerThreadId == null || lockOwnerThreadId == currentThreadId) {
// if nobody owns this lock, lock cycle is impossible
// if a current thread owns this lock, we let Guice to handle it
return ImmutableListMultimap.of();
}
ListMultimap<Long, ID> potentialLocksCycle = Multimaps.newListMultimap(
new LinkedHashMap<Long, Collection<ID>>(),
new Supplier<List<ID>>() {
@Override
public List<ID> get() {
return Lists.newArrayList();
}
});
// lock that is a part of a potential locks cycle, starts with current lock
ReentrantCycleDetectingLock lockOwnerWaitingOn = this;
// try to find a dependency path between lock's owner thread and a current thread
while (lockOwnerWaitingOn != null && lockOwnerWaitingOn.lockOwnerThreadId != null) {
Long threadOwnerThreadWaits = lockOwnerWaitingOn.lockOwnerThreadId;
// in case locks cycle exists lock we're waiting for is part of it
potentialLocksCycle.putAll(threadOwnerThreadWaits,
getAllLockIdsAfter(threadOwnerThreadWaits, lockOwnerWaitingOn));
if (threadOwnerThreadWaits == currentThreadId) {
// owner thread depends on current thread, cycle detected
return potentialLocksCycle;
}
// going for the next thread we wait on indirectly
lockOwnerWaitingOn = lockThreadIsWaitingOn.get(threadOwnerThreadWaits);
}
// no dependency path from an owner thread to a current thread
return ImmutableListMultimap.of();
}
/**
* Return locks owned by a thread after a lock specified, inclusive.
*/
private List<ID> getAllLockIdsAfter(long threadId, ReentrantCycleDetectingLock lock) {
List<ID> ids = Lists.newArrayList();
boolean found = false;
Collection<ReentrantCycleDetectingLock> ownedLocks = locksOwnedByThread.get(threadId);
Preconditions.checkNotNull(ownedLocks,
"Internal error: No locks were found taken by a thread");
for (ReentrantCycleDetectingLock ownedLock : ownedLocks) {
if (ownedLock == lock) {
found = true;
}
if (found) {
ids.add(ownedLock.userLockId);
}
}
Preconditions.checkState(found, "Internal error: We can not find locks that "
+ "created a cycle that we detected");
return ids;
}
@Override
public String toString() {
// copy is made to prevent a data race
// no synchronization is used, potentially stale data, should be good enough
Long localLockOwnerThreadId = this.lockOwnerThreadId;
if (localLockOwnerThreadId != null) {
return String.format("CycleDetectingLock[%s][locked by %s]",
userLockId, localLockOwnerThreadId);
} else {
return String.format("CycleDetectingLock[%s][unlocked]", userLockId);
}
}
}
}
}

View file

@ -0,0 +1,57 @@
package com.google.inject.internal;
import com.google.inject.spi.InjectionPoint;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
/**
* Produces construction proxies that invoke the class constructor.
*/
final class DefaultConstructionProxyFactory<T> implements ConstructionProxyFactory<T> {
private final InjectionPoint injectionPoint;
/**
* @param injectionPoint an injection point whose member is a constructor of {@code T}.
*/
DefaultConstructionProxyFactory(InjectionPoint injectionPoint) {
this.injectionPoint = injectionPoint;
}
public ConstructionProxy<T> create() {
@SuppressWarnings("unchecked") // the injection point is for a constructor of T
final Constructor<T> constructor = (Constructor<T>) injectionPoint.getMember();
// Use FastConstructor if the constructor is public.
if (Modifier.isPublic(constructor.getModifiers())) {
Class<T> classToConstruct = constructor.getDeclaringClass();
if (!Modifier.isPublic(classToConstruct.getModifiers())) {
constructor.setAccessible(true);
}
} else {
constructor.setAccessible(true);
}
return new ConstructionProxy<T>() {
public T newInstance(Object... arguments) throws InvocationTargetException {
try {
return constructor.newInstance(arguments);
} catch (InstantiationException e) {
throw new AssertionError(e); // shouldn't happen, we know this is a concrete type
} catch (IllegalAccessException e) {
throw new AssertionError(e); // a security manager is blocking us, we're hosed
}
}
public InjectionPoint getInjectionPoint() {
return injectionPoint;
}
public Constructor<T> getConstructor() {
return constructor;
}
};
}
}

View file

@ -0,0 +1,45 @@
package com.google.inject.internal;
import com.google.common.collect.Lists;
import com.google.inject.Key;
import com.google.inject.MembersInjector;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.Element;
import com.google.inject.spi.MembersInjectorLookup;
import com.google.inject.spi.ProviderLookup;
import java.util.List;
/**
* Returns providers and members injectors that haven't yet been initialized. As a part of injector
* creation it's necessary to {@link #initialize initialize} these lookups.
*/
final class DeferredLookups implements Lookups {
private final InjectorImpl injector;
private final List<Element> lookups = Lists.newArrayList();
DeferredLookups(InjectorImpl injector) {
this.injector = injector;
}
/**
* Initialize the specified lookups, either immediately or when the injector is created.
*/
void initialize(Errors errors) {
injector.lookups = injector;
new LookupProcessor(errors).process(injector, lookups);
}
public <T> Provider<T> getProvider(Key<T> key) {
ProviderLookup<T> lookup = new ProviderLookup<T>(key, key);
lookups.add(lookup);
return lookup.getProvider();
}
public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> type) {
MembersInjectorLookup<T> lookup = new MembersInjectorLookup<T>(type, type);
lookups.add(lookup);
return lookup.getMembersInjector();
}
}

View file

@ -0,0 +1,15 @@
package com.google.inject.internal;
/**
* Something that needs some delayed initialization, typically
* a binding or internal factory that needs to be created & put
* into the bindings map & then initialized later.
*/
interface DelayedInitialize {
/**
* Initializes this binding, throwing any errors if necessary.
*/
void initialize(InjectorImpl injector, Errors errors) throws ErrorsException;
}

View file

@ -0,0 +1,44 @@
package com.google.inject.internal;
import com.google.common.base.Preconditions;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
class DelegatingInvocationHandler<T> implements InvocationHandler {
private volatile boolean initialized;
private T delegate;
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
try {
// checking volatile field for synchronization
Preconditions.checkState(initialized,
"This is a proxy used to support"
+ " circular references. The object we're"
+ " proxying is not constructed yet. Please wait until after"
+ " injection has completed to use this object.");
Preconditions.checkNotNull(delegate,
"This is a proxy used to support"
+ " circular references. The object we're "
+ " proxying is initialized to null."
+ " No methods can be called.");
return method.invoke(delegate, args);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
void setDelegate(T delegate) {
this.delegate = delegate;
initialized = true;
}
}

View file

@ -0,0 +1,98 @@
package com.google.inject.internal;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.inject.Key;
import com.google.inject.MembersInjector;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.InjectionListener;
import com.google.inject.spi.Message;
import com.google.inject.spi.TypeEncounter;
import java.util.List;
import static com.google.common.base.Preconditions.checkState;
final class EncounterImpl<T> implements TypeEncounter<T> {
private final Errors errors;
private final Lookups lookups;
private List<MembersInjector<? super T>> membersInjectors; // lazy
private List<InjectionListener<? super T>> injectionListeners; // lazy
private boolean valid = true;
EncounterImpl(Errors errors, Lookups lookups) {
this.errors = errors;
this.lookups = lookups;
}
void invalidate() {
valid = false;
}
ImmutableSet<MembersInjector<? super T>> getMembersInjectors() {
return membersInjectors == null
? ImmutableSet.<MembersInjector<? super T>>of()
: ImmutableSet.copyOf(membersInjectors);
}
ImmutableSet<InjectionListener<? super T>> getInjectionListeners() {
return injectionListeners == null
? ImmutableSet.<InjectionListener<? super T>>of()
: ImmutableSet.copyOf(injectionListeners);
}
public void register(MembersInjector<? super T> membersInjector) {
checkState(valid, "Encounters may not be used after hear() returns.");
if (membersInjectors == null) {
membersInjectors = Lists.newArrayList();
}
membersInjectors.add(membersInjector);
}
public void register(InjectionListener<? super T> injectionListener) {
checkState(valid, "Encounters may not be used after hear() returns.");
if (injectionListeners == null) {
injectionListeners = Lists.newArrayList();
}
injectionListeners.add(injectionListener);
}
public void addError(String message, Object... arguments) {
checkState(valid, "Encounters may not be used after hear() returns.");
errors.addMessage(message, arguments);
}
public void addError(Throwable t) {
checkState(valid, "Encounters may not be used after hear() returns.");
errors.errorInUserCode(t, "An exception was caught and reported. Message: %s", t.getMessage());
}
public void addError(Message message) {
checkState(valid, "Encounters may not be used after hear() returns.");
errors.addMessage(message);
}
public <T> Provider<T> getProvider(Key<T> key) {
checkState(valid, "Encounters may not be used after hear() returns.");
return lookups.getProvider(key);
}
public <T> Provider<T> getProvider(Class<T> type) {
return getProvider(Key.get(type));
}
public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral) {
checkState(valid, "Encounters may not be used after hear() returns.");
return lookups.getMembersInjector(typeLiteral);
}
public <T> MembersInjector<T> getMembersInjector(Class<T> type) {
return getMembersInjector(TypeLiteral.get(type));
}
}

View file

@ -0,0 +1,817 @@
package com.google.inject.internal;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.common.collect.Ordering;
import com.google.inject.ConfigurationException;
import com.google.inject.CreationException;
import com.google.inject.Key;
import com.google.inject.MembersInjector;
import com.google.inject.Provider;
import com.google.inject.Provides;
import com.google.inject.ProvisionException;
import com.google.inject.Scope;
import com.google.inject.TypeLiteral;
import com.google.inject.internal.util.Classes;
import com.google.inject.internal.util.SourceProvider;
import com.google.inject.internal.util.StackTraceElements;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.ElementSource;
import com.google.inject.spi.InjectionListener;
import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.Message;
import com.google.inject.spi.ScopeBinding;
import com.google.inject.spi.TypeConverterBinding;
import com.google.inject.spi.TypeListenerBinding;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Member;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Collections;
import java.util.Formatter;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
/**
* A collection of error messages. If this type is passed as a method parameter, the method is
* considered to have executed successfully only if new errors were not added to this collection.
*
* <p>Errors can be chained to provide additional context. To add context, call {@link #withSource}
* to create a new Errors instance that contains additional context. All messages added to the
* returned instance will contain full context.
*
* <p>To avoid messages with redundant context, {@link #withSource} should be added sparingly. A
* good rule of thumb is to assume a method's caller has already specified enough context to
* identify that method. When calling a method that's defined in a different context, call that
* method with an errors object that includes its context.
*
*/
public final class Errors {
private static final Set<Dependency<?>> warnedDependencies =
Collections.newSetFromMap(new ConcurrentHashMap<Dependency<?>, Boolean>());
private static final String CONSTRUCTOR_RULES =
"Classes must have either one (and only one) constructor "
+ "annotated with @Inject or a zero-argument constructor that is not private.";
private static final Collection<Converter<?>> converters = ImmutableList.of(
new Converter<Class>(Class.class) {
@Override
public String toString(Class c) {
return c.getName();
}
},
new Converter<Member>(Member.class) {
@Override
public String toString(Member member) {
return Classes.toString(member);
}
},
new Converter<Key>(Key.class) {
@Override
public String toString(Key key) {
if (key.getAnnotationType() != null) {
return key.getTypeLiteral() + " annotated with "
+ (key.getAnnotation() != null ? key.getAnnotation() : key.getAnnotationType());
} else {
return key.getTypeLiteral().toString();
}
}
});
/**
* The root errors object. Used to access the list of error messages.
*/
private final Errors root;
/**
* The parent errors object. Used to obtain the chain of source objects.
*/
private final Errors parent;
/**
* The leaf source for errors added here.
*/
private final Object source;
/**
* null unless (root == this) and error messages exist. Never an empty list.
*/
private List<Message> errors; // lazy, use getErrorsForAdd()
public Errors() {
this.root = this;
this.parent = null;
this.source = SourceProvider.UNKNOWN_SOURCE;
}
public Errors(Object source) {
this.root = this;
this.parent = null;
this.source = source;
}
private Errors(Errors parent, Object source) {
this.root = parent.root;
this.parent = parent;
this.source = source;
}
public static Collection<Message> getMessagesFromThrowable(Throwable throwable) {
if (throwable instanceof ProvisionException) {
return ((ProvisionException) throwable).getErrorMessages();
} else if (throwable instanceof ConfigurationException) {
return ((ConfigurationException) throwable).getErrorMessages();
} else if (throwable instanceof CreationException) {
return ((CreationException) throwable).getErrorMessages();
} else {
return ImmutableSet.of();
}
}
public static String format(String messageFormat, Object... arguments) {
for (int i = 0; i < arguments.length; i++) {
arguments[i] = Errors.convert(arguments[i]);
}
return String.format(messageFormat, arguments);
}
/**
* Returns the formatted message for an exception with the specified messages.
*/
public static String format(String heading, Collection<Message> errorMessages) {
Formatter fmt = new Formatter().format(heading).format(":%n%n");
int index = 1;
boolean displayCauses = getOnlyCause(errorMessages) == null;
for (Message errorMessage : errorMessages) {
fmt.format("%s) %s%n", index++, errorMessage.getMessage());
List<Object> dependencies = errorMessage.getSources();
for (int i = dependencies.size() - 1; i >= 0; i--) {
Object source = dependencies.get(i);
formatSource(fmt, source);
}
Throwable cause = errorMessage.getCause();
if (displayCauses && cause != null) {
StringWriter writer = new StringWriter();
cause.printStackTrace(new PrintWriter(writer));
fmt.format("Caused by: %s", writer.getBuffer());
}
fmt.format("%n");
}
if (errorMessages.size() == 1) {
fmt.format("1 error");
} else {
fmt.format("%s errors", errorMessages.size());
}
return fmt.toString();
}
/**
* Returns the cause throwable if there is exactly one cause in {@code messages}. If there are
* zero or multiple messages with causes, null is returned.
*/
public static Throwable getOnlyCause(Collection<Message> messages) {
Throwable onlyCause = null;
for (Message message : messages) {
Throwable messageCause = message.getCause();
if (messageCause == null) {
continue;
}
if (onlyCause != null) {
return null;
}
onlyCause = messageCause;
}
return onlyCause;
}
public static Object convert(Object o) {
ElementSource source = null;
if (o instanceof ElementSource) {
source = (ElementSource) o;
o = source.getDeclaringSource();
}
return convert(o, source);
}
public static Object convert(Object o, ElementSource source) {
for (Converter<?> converter : converters) {
if (converter.appliesTo(o)) {
return appendModules(converter.convert(o), source);
}
}
return appendModules(o, source);
}
private static Object appendModules(Object source, ElementSource elementSource) {
String modules = moduleSourceString(elementSource);
if (modules.length() == 0) {
return source;
} else {
return source + modules;
}
}
private static String moduleSourceString(ElementSource elementSource) {
// if we only have one module (or don't know what they are), then don't bother
// reporting it, because the source already is going to report exactly that module.
if (elementSource == null) {
return "";
}
List<String> modules = Lists.newArrayList(elementSource.getModuleClassNames());
// Insert any original element sources w/ module info into the path.
while (elementSource.getOriginalElementSource() != null) {
elementSource = elementSource.getOriginalElementSource();
modules.addAll(0, elementSource.getModuleClassNames());
}
if (modules.size() <= 1) {
return "";
}
// Ideally we'd do:
// return Joiner.on(" -> ")
// .appendTo(new StringBuilder(" (via modules: "), Lists.reverse(modules))
// .append(")").toString();
// ... but for some reason we can't find Lists.reverse, so do it the boring way.
StringBuilder builder = new StringBuilder(" (via modules: ");
for (int i = modules.size() - 1; i >= 0; i--) {
builder.append(modules.get(i));
if (i != 0) {
builder.append(" -> ");
}
}
builder.append(")");
return builder.toString();
}
public static void formatSource(Formatter formatter, Object source) {
ElementSource elementSource = null;
if (source instanceof ElementSource) {
elementSource = (ElementSource) source;
source = elementSource.getDeclaringSource();
}
formatSource(formatter, source, elementSource);
}
public static void formatSource(Formatter formatter, Object source, ElementSource elementSource) {
String modules = moduleSourceString(elementSource);
if (source instanceof Dependency) {
Dependency<?> dependency = (Dependency<?>) source;
InjectionPoint injectionPoint = dependency.getInjectionPoint();
if (injectionPoint != null) {
formatInjectionPoint(formatter, dependency, injectionPoint, elementSource);
} else {
formatSource(formatter, dependency.getKey(), elementSource);
}
} else if (source instanceof InjectionPoint) {
formatInjectionPoint(formatter, null, (InjectionPoint) source, elementSource);
} else if (source instanceof Class) {
formatter.format(" at %s%s%n", StackTraceElements.forType((Class<?>) source), modules);
} else if (source instanceof Member) {
formatter.format(" at %s%s%n", StackTraceElements.forMember((Member) source), modules);
} else if (source instanceof TypeLiteral) {
formatter.format(" while locating %s%s%n", source, modules);
} else if (source instanceof Key) {
Key<?> key = (Key<?>) source;
formatter.format(" while locating %s%n", convert(key, elementSource));
} else if (source instanceof Thread) {
formatter.format(" in thread %s%n", source);
} else {
formatter.format(" at %s%s%n", source, modules);
}
}
public static void formatInjectionPoint(Formatter formatter, Dependency<?> dependency,
InjectionPoint injectionPoint, ElementSource elementSource) {
Member member = injectionPoint.getMember();
Class<? extends Member> memberType = Classes.memberType(member);
if (memberType == Field.class) {
dependency = injectionPoint.getDependencies().get(0);
formatter.format(" while locating %s%n", convert(dependency.getKey(), elementSource));
formatter.format(" for field at %s%n", StackTraceElements.forMember(member));
} else if (dependency != null) {
formatter.format(" while locating %s%n", convert(dependency.getKey(), elementSource));
formatter.format(" for parameter %s at %s%n",
dependency.getParameterIndex(), StackTraceElements.forMember(member));
} else {
formatSource(formatter, injectionPoint.getMember());
}
}
/**
* Returns an instance that uses {@code source} as a reference point for newly added errors.
*/
public Errors withSource(Object source) {
return source == this.source || source == SourceProvider.UNKNOWN_SOURCE
? this
: new Errors(this, source);
}
/**
* We use a fairly generic error message here. The motivation is to share the
* same message for both bind time errors:
* <pre><code>Guice.createInjector(new AbstractModule() {
* public void configure() {
* bind(Runnable.class);
* }
* }</code></pre>
* ...and at provide-time errors:
* <pre><code>Guice.createInjector().getInstance(Runnable.class);</code></pre>
* Otherwise we need to know who's calling when resolving a just-in-time
* binding, which makes things unnecessarily complex.
*/
public Errors missingImplementation(Key key) {
return addMessage("No implementation for %s was bound.", key);
}
public Errors jitDisabled(Key key) {
return addMessage("Explicit bindings are required and %s is not explicitly bound.", key);
}
public Errors jitDisabledInParent(Key<?> key) {
return addMessage(
"Explicit bindings are required and %s would be bound in a parent injector.%n"
+ "Please add an explicit binding for it, either in the child or the parent.",
key);
}
public Errors atInjectRequired(Class clazz) {
return addMessage(
"Explicit @Inject annotations are required on constructors,"
+ " but %s has no constructors annotated with @Inject.",
clazz);
}
public Errors converterReturnedNull(String stringValue, Object source,
TypeLiteral<?> type, TypeConverterBinding typeConverterBinding) {
return addMessage("Received null converting '%s' (bound at %s) to %s%n"
+ " using %s.",
stringValue, convert(source), type, typeConverterBinding);
}
public Errors conversionTypeError(String stringValue, Object source, TypeLiteral<?> type,
TypeConverterBinding typeConverterBinding, Object converted) {
return addMessage("Type mismatch converting '%s' (bound at %s) to %s%n"
+ " using %s.%n"
+ " Converter returned %s.",
stringValue, convert(source), type, typeConverterBinding, converted);
}
public Errors conversionError(String stringValue, Object source,
TypeLiteral<?> type, TypeConverterBinding typeConverterBinding, RuntimeException cause) {
return errorInUserCode(cause, "Error converting '%s' (bound at %s) to %s%n"
+ " using %s.%n"
+ " Reason: %s",
stringValue, convert(source), type, typeConverterBinding, cause);
}
public Errors ambiguousTypeConversion(String stringValue, Object source, TypeLiteral<?> type,
TypeConverterBinding a, TypeConverterBinding b) {
return addMessage("Multiple converters can convert '%s' (bound at %s) to %s:%n"
+ " %s and%n"
+ " %s.%n"
+ " Please adjust your type converter configuration to avoid overlapping matches.",
stringValue, convert(source), type, a, b);
}
public Errors bindingToProvider() {
return addMessage("Binding to Provider is not allowed.");
}
public Errors subtypeNotProvided(Class<? extends Provider<?>> providerType,
Class<?> type) {
return addMessage("%s doesn't provide instances of %s.", providerType, type);
}
public Errors notASubtype(Class<?> implementationType, Class<?> type) {
return addMessage("%s doesn't extend %s.", implementationType, type);
}
public Errors recursiveImplementationType() {
return addMessage("@ImplementedBy points to the same class it annotates.");
}
public Errors recursiveProviderType() {
return addMessage("@ProvidedBy points to the same class it annotates.");
}
public Errors missingRuntimeRetention(Class<? extends Annotation> annotation) {
return addMessage(format("Please annotate %s with @Retention(RUNTIME).", annotation));
}
public Errors missingScopeAnnotation(Class<? extends Annotation> annotation) {
return addMessage(format("Please annotate %s with @ScopeAnnotation.", annotation));
}
public Errors optionalConstructor(Constructor constructor) {
return addMessage("%s is annotated @Inject(optional=true), "
+ "but constructors cannot be optional.", constructor);
}
public Errors cannotBindToGuiceType(String simpleName) {
return addMessage("Binding to core guice framework type is not allowed: %s.", simpleName);
}
public Errors scopeNotFound(Class<? extends Annotation> scopeAnnotation) {
return addMessage("No scope is bound to %s.", scopeAnnotation);
}
public Errors scopeAnnotationOnAbstractType(
Class<? extends Annotation> scopeAnnotation, Class<?> type, Object source) {
return addMessage("%s is annotated with %s, but scope annotations are not supported "
+ "for abstract types.%n Bound at %s.", type, scopeAnnotation, convert(source));
}
public Errors misplacedBindingAnnotation(Member member, Annotation bindingAnnotation) {
return addMessage("%s is annotated with %s, but binding annotations should be applied "
+ "to its parameters instead.", member, bindingAnnotation);
}
public Errors missingConstructor(Class<?> implementation) {
return addMessage("Could not find a suitable constructor in %s. " + CONSTRUCTOR_RULES,
implementation);
}
public Errors tooManyConstructors(Class<?> implementation) {
return addMessage("%s has more than one constructor annotated with @Inject. "
+ CONSTRUCTOR_RULES, implementation);
}
public Errors constructorNotDefinedByType(Constructor<?> constructor, TypeLiteral<?> type) {
return addMessage("%s does not define %s", type, constructor);
}
public Errors duplicateScopes(ScopeBinding existing,
Class<? extends Annotation> annotationType, Scope scope) {
return addMessage("Scope %s is already bound to %s at %s.%n Cannot bind %s.",
existing.getScope(), annotationType, existing.getSource(), scope);
}
public Errors voidProviderMethod() {
return addMessage("Provider methods must return a value. Do not return void.");
}
public Errors missingConstantValues() {
return addMessage("Missing constant value. Please call to(...).");
}
public Errors cannotInjectInnerClass(Class<?> type) {
return addMessage("Injecting into inner classes is not supported. "
+ "Please use a 'static' class (top-level or nested) instead of %s.", type);
}
public Errors duplicateBindingAnnotations(Member member,
Class<? extends Annotation> a, Class<? extends Annotation> b) {
return addMessage("%s has more than one annotation annotated with @BindingAnnotation: "
+ "%s and %s", member, a, b);
}
public Errors staticInjectionOnInterface(Class<?> clazz) {
return addMessage("%s is an interface, but interfaces have no static injection points.", clazz);
}
public Errors cannotInjectFinalField(Field field) {
return addMessage("Injected field %s cannot be final.", field);
}
public Errors cannotInjectAbstractMethod(Method method) {
return addMessage("Injected method %s cannot be abstract.", method);
}
public Errors cannotInjectNonVoidMethod(Method method) {
return addMessage("Injected method %s must return void.", method);
}
public Errors cannotInjectMethodWithTypeParameters(Method method) {
return addMessage("Injected method %s cannot declare type parameters of its own.", method);
}
public Errors duplicateScopeAnnotations(
Class<? extends Annotation> a, Class<? extends Annotation> b) {
return addMessage("More than one scope annotation was found: %s and %s.", a, b);
}
public Errors recursiveBinding() {
return addMessage("Binding points to itself.");
}
public Errors bindingAlreadySet(Key<?> key, Object source) {
return addMessage("A binding to %s was already configured at %s.", key, convert(source));
}
public Errors jitBindingAlreadySet(Key<?> key) {
return addMessage("A just-in-time binding to %s was already configured on a parent injector.", key);
}
public Errors childBindingAlreadySet(Key<?> key, Set<Object> sources) {
Formatter allSources = new Formatter();
for (Object source : sources) {
if (source == null) {
allSources.format("%n (bound by a just-in-time binding)");
} else {
allSources.format("%n bound at %s", source);
}
}
Errors errors = addMessage(
"Unable to create binding for %s."
+ " It was already configured on one or more child injectors or private modules"
+ "%s%n"
+ " If it was in a PrivateModule, did you forget to expose the binding?",
key, allSources.out());
return errors;
}
public Errors errorCheckingDuplicateBinding(Key<?> key, Object source, Throwable t) {
return addMessage(
"A binding to %s was already configured at %s and an error was thrown "
+ "while checking duplicate bindings. Error: %s",
key, convert(source), t);
}
public Errors errorInjectingMethod(Throwable cause) {
return errorInUserCode(cause, "Error injecting method, %s", cause);
}
public Errors errorNotifyingTypeListener(TypeListenerBinding listener,
TypeLiteral<?> type, Throwable cause) {
return errorInUserCode(cause,
"Error notifying TypeListener %s (bound at %s) of %s.%n"
+ " Reason: %s",
listener.getListener(), convert(listener.getSource()), type, cause);
}
public Errors errorInjectingConstructor(Throwable cause) {
return errorInUserCode(cause, "Error injecting constructor, %s", cause);
}
public Errors errorInProvider(RuntimeException runtimeException) {
Throwable unwrapped = unwrap(runtimeException);
return errorInUserCode(unwrapped, "Error in custom provider, %s", unwrapped);
}
public Errors errorInUserInjector(
MembersInjector<?> listener, TypeLiteral<?> type, RuntimeException cause) {
return errorInUserCode(cause, "Error injecting %s using %s.%n"
+ " Reason: %s", type, listener, cause);
}
public Errors errorNotifyingInjectionListener(
InjectionListener<?> listener, TypeLiteral<?> type, RuntimeException cause) {
return errorInUserCode(cause, "Error notifying InjectionListener %s of %s.%n"
+ " Reason: %s", listener, type, cause);
}
public Errors exposedButNotBound(Key<?> key) {
return addMessage("Could not expose() %s, it must be explicitly bound.", key);
}
public Errors keyNotFullySpecified(TypeLiteral<?> typeLiteral) {
return addMessage("%s cannot be used as a key; It is not fully specified.", typeLiteral);
}
public Errors errorEnhancingClass(Class<?> clazz, Throwable cause) {
return errorInUserCode(cause, "Unable to method intercept: %s", clazz);
}
public Errors errorInUserCode(Throwable cause, String messageFormat, Object... arguments) {
Collection<Message> messages = getMessagesFromThrowable(cause);
if (!messages.isEmpty()) {
return merge(messages);
} else {
return addMessage(cause, messageFormat, arguments);
}
}
private Throwable unwrap(RuntimeException runtimeException) {
if (runtimeException instanceof Exceptions.UnhandledCheckedUserException) {
return runtimeException.getCause();
} else {
return runtimeException;
}
}
public Errors cannotInjectRawProvider() {
return addMessage("Cannot inject a Provider that has no type parameter");
}
public Errors cannotInjectRawMembersInjector() {
return addMessage("Cannot inject a MembersInjector that has no type parameter");
}
public Errors cannotInjectTypeLiteralOf(Type unsupportedType) {
return addMessage("Cannot inject a TypeLiteral of %s", unsupportedType);
}
public Errors cannotInjectRawTypeLiteral() {
return addMessage("Cannot inject a TypeLiteral that has no type parameter");
}
public Errors cannotSatisfyCircularDependency(Class<?> expectedType) {
return addMessage(
"Tried proxying %s to support a circular dependency, but it is not an interface.",
expectedType);
}
public Errors circularProxiesDisabled(Class<?> expectedType) {
return addMessage(
"Tried proxying %s to support a circular dependency, but circular proxies are disabled.",
expectedType);
}
public void throwCreationExceptionIfErrorsExist() {
if (!hasErrors()) {
return;
}
throw new CreationException(getMessages());
}
public void throwConfigurationExceptionIfErrorsExist() {
if (!hasErrors()) {
return;
}
throw new ConfigurationException(getMessages());
}
public void throwProvisionExceptionIfErrorsExist() {
if (!hasErrors()) {
return;
}
throw new ProvisionException(getMessages());
}
private Message merge(Message message) {
List<Object> sources = Lists.newArrayList();
sources.addAll(getSources());
sources.addAll(message.getSources());
return new Message(sources, message.getMessage(), message.getCause());
}
public Errors merge(Collection<Message> messages) {
for (Message message : messages) {
addMessage(merge(message));
}
return this;
}
public Errors merge(Errors moreErrors) {
if (moreErrors.root == root || moreErrors.root.errors == null) {
return this;
}
merge(moreErrors.root.errors);
return this;
}
public List<Object> getSources() {
List<Object> sources = Lists.newArrayList();
for (Errors e = this; e != null; e = e.parent) {
if (e.source != SourceProvider.UNKNOWN_SOURCE) {
sources.add(0, e.source);
}
}
return sources;
}
public void throwIfNewErrors(int expectedSize) throws ErrorsException {
if (size() == expectedSize) {
return;
}
throw toException();
}
public ErrorsException toException() {
return new ErrorsException(this);
}
public boolean hasErrors() {
return root.errors != null;
}
public Errors addMessage(String messageFormat, Object... arguments) {
return addMessage(null, messageFormat, arguments);
}
private Errors addMessage(Throwable cause, String messageFormat, Object... arguments) {
String message = format(messageFormat, arguments);
addMessage(new Message(getSources(), message, cause));
return this;
}
public Errors addMessage(Message message) {
if (root.errors == null) {
root.errors = Lists.newArrayList();
}
root.errors.add(message);
return this;
}
public List<Message> getMessages() {
if (root.errors == null) {
return ImmutableList.of();
}
return new Ordering<Message>() {
@Override
public int compare(Message a, Message b) {
return a.getSource().compareTo(b.getSource());
}
}.sortedCopy(root.errors);
}
/**
* Returns {@code value} if it is non-null allowed to be null. Otherwise a message is added and
* an {@code ErrorsException} is thrown.
*/
public <T> T checkForNull(T value, Object source, Dependency<?> dependency)
throws ErrorsException {
if (value != null || dependency.isNullable()) {
return value;
}
// Hack to allow null parameters to @Provides methods, for backwards compatibility.
if (dependency.getInjectionPoint().getMember() instanceof Method) {
Method annotated = (Method) dependency.getInjectionPoint().getMember();
if (annotated.isAnnotationPresent(Provides.class)) {
switch (InternalFlags.getNullableProvidesOption()) {
case ERROR:
break; // break out & let the below exception happen
case IGNORE:
return value; // user doesn't care about injecting nulls to non-@Nullables.
case WARN:
// Warn only once, otherwise we spam logs too much.
if (!warnedDependencies.add(dependency)) {
return value;
}
/*logger.log(Level.WARNING,
"Guice injected null into parameter {0} of {1} (a {2}), please mark it @Nullable."
+ " Use -Dguice_check_nullable_provides_params=ERROR to turn this into an"
+ " error.",
new Object[]{
dependency.getParameterIndex(),
convert(dependency.getInjectionPoint().getMember()),
convert(dependency.getKey())});*/
return null; // log & exit.
}
}
}
int parameterIndex = dependency.getParameterIndex();
String parameterName = (parameterIndex != -1)
? "parameter " + parameterIndex + " of "
: "";
addMessage("null returned by binding at %s%n but %s%s is not @Nullable",
source, parameterName, dependency.getInjectionPoint().getMember());
throw toException();
}
public int size() {
return root.errors == null ? 0 : root.errors.size();
}
private static abstract class Converter<T> {
final Class<T> type;
Converter(Class<T> type) {
this.type = type;
}
boolean appliesTo(Object o) {
return o != null && type.isAssignableFrom(o.getClass());
}
String convert(Object o) {
return toString(type.cast(o));
}
abstract String toString(T t);
}
}

View file

@ -0,0 +1,20 @@
package com.google.inject.internal;
/**
* Indicates that a result could not be returned while preparing or resolving a binding. The caller
* should {@link Errors#merge(Errors) merge} the errors from this exception with their existing
* errors.
*/
@SuppressWarnings("serial")
public class ErrorsException extends Exception {
private final Errors errors;
public ErrorsException(Errors errors) {
this.errors = errors;
}
public Errors getErrors() {
return errors;
}
}

View file

@ -0,0 +1,46 @@
package com.google.inject.internal;
/**
* Rethrows user-code exceptions in wrapped exceptions so that Errors can target the correct
* exception.
*/
class Exceptions {
/**
* Rethrows the exception (or it's cause, if it has one) directly if possible.
* If it was a checked exception, this wraps the exception in a stack trace
* with no frames, so that the exception is shown immediately with no frames
* above it.
*/
public static RuntimeException rethrowCause(Throwable throwable) {
Throwable cause = throwable;
if (cause.getCause() != null) {
cause = cause.getCause();
}
return rethrow(cause);
}
/**
* Rethrows the exception.
*/
public static RuntimeException rethrow(Throwable throwable) {
if (throwable instanceof RuntimeException) {
throw (RuntimeException) throwable;
} else if (throwable instanceof Error) {
throw (Error) throwable;
} else {
throw new UnhandledCheckedUserException(throwable);
}
}
/**
* A marker exception class that we look for in order to unwrap the exception
* into the user exception, to provide a cleaner stack trace.
*/
@SuppressWarnings("serial")
static class UnhandledCheckedUserException extends RuntimeException {
public UnhandledCheckedUserException(Throwable cause) {
super(cause);
}
}
}

View file

@ -0,0 +1,52 @@
package com.google.inject.internal;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Binder;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.ExposedBinding;
import com.google.inject.spi.PrivateElements;
import java.util.Set;
public final class ExposedBindingImpl<T> extends BindingImpl<T> implements ExposedBinding<T> {
private final PrivateElements privateElements;
public ExposedBindingImpl(InjectorImpl injector, Object source, Key<T> key,
InternalFactory<T> factory, PrivateElements privateElements) {
super(injector, key, source, factory, Scoping.UNSCOPED);
this.privateElements = privateElements;
}
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
return visitor.visit(this);
}
public Set<Dependency<?>> getDependencies() {
return ImmutableSet.<Dependency<?>>of(Dependency.get(Key.get(Injector.class)));
}
public PrivateElements getPrivateElements() {
return privateElements;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(ExposedBinding.class)
.add("key", getKey())
.add("source", getSource())
.add("privateElements", privateElements)
.toString();
}
public void applyTo(Binder binder) {
throw new UnsupportedOperationException("This element represents a synthetic binding.");
}
// Purposely does not override equals/hashcode, because exposed bindings are only equal to
// themselves right now -- that is, there cannot be "duplicate" exposed bindings.
}

View file

@ -0,0 +1,40 @@
package com.google.inject.internal;
import com.google.inject.Key;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.PrivateElements;
/**
* This factory exists in a parent injector. When invoked, it retrieves its value from a child
* injector.
*/
final class ExposedKeyFactory<T> implements InternalFactory<T>, CreationListener {
private final Key<T> key;
private final PrivateElements privateElements;
private BindingImpl<T> delegate;
ExposedKeyFactory(Key<T> key, PrivateElements privateElements) {
this.key = key;
this.privateElements = privateElements;
}
public void notify(Errors errors) {
InjectorImpl privateInjector = (InjectorImpl) privateElements.getInjector();
BindingImpl<T> explicitBinding = privateInjector.state.getExplicitBinding(key);
// validate that the child injector has its own factory. If the getInternalFactory() returns
// this, then that child injector doesn't have a factory (and getExplicitBinding has returned
// its parent's binding instead
if (explicitBinding.getInternalFactory() == this) {
errors.withSource(explicitBinding.getSource()).exposedButNotBound(key);
return;
}
this.delegate = explicitBinding;
}
public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
throws ErrorsException {
return delegate.getInternalFactory().get(errors, context, dependency, linked);
}
}

View file

@ -0,0 +1,54 @@
package com.google.inject.internal;
import com.google.common.base.Preconditions;
import com.google.inject.Binder;
import com.google.inject.Key;
import com.google.inject.binder.AnnotatedElementBuilder;
import java.lang.annotation.Annotation;
/**
* For private binder's expose() method.
*/
public class ExposureBuilder<T> implements AnnotatedElementBuilder {
private final Binder binder;
private final Object source;
private Key<T> key;
public ExposureBuilder(Binder binder, Object source, Key<T> key) {
this.binder = binder;
this.source = source;
this.key = key;
}
protected void checkNotAnnotated() {
if (key.getAnnotationType() != null) {
binder.addError(AbstractBindingBuilder.ANNOTATION_ALREADY_SPECIFIED);
}
}
public void annotatedWith(Class<? extends Annotation> annotationType) {
Preconditions.checkNotNull(annotationType, "annotationType");
checkNotAnnotated();
key = Key.get(key.getTypeLiteral(), annotationType);
}
public void annotatedWith(Annotation annotation) {
Preconditions.checkNotNull(annotation, "annotation");
checkNotAnnotated();
key = Key.get(key.getTypeLiteral(), annotation);
}
public Key<?> getKey() {
return key;
}
public Object getSource() {
return source;
}
@Override
public String toString() {
return "AnnotatedElementBuilder";
}
}

View file

@ -0,0 +1,53 @@
package com.google.inject.internal;
import com.google.common.base.MoreObjects;
import com.google.inject.Key;
import com.google.inject.internal.InjectorImpl.JitLimitation;
import com.google.inject.spi.Dependency;
/**
* A placeholder which enables us to swap in the real factory once the injector is created.
* Used for a linked binding, so that getting the linked binding returns the link's factory.
*/
final class FactoryProxy<T> implements InternalFactory<T>, CreationListener {
private final InjectorImpl injector;
private final Key<T> key;
private final Key<? extends T> targetKey;
private final Object source;
private InternalFactory<? extends T> targetFactory;
FactoryProxy(InjectorImpl injector, Key<T> key, Key<? extends T> targetKey, Object source) {
this.injector = injector;
this.key = key;
this.targetKey = targetKey;
this.source = source;
}
public void notify(final Errors errors) {
try {
targetFactory = injector.getInternalFactory(targetKey, errors.withSource(source), JitLimitation.NEW_OR_EXISTING_JIT);
} catch (ErrorsException e) {
errors.merge(e.getErrors());
}
}
public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
throws ErrorsException {
context.pushState(targetKey, source);
try {
return targetFactory.get(errors.withSource(targetKey), context, dependency, true);
} finally {
context.popState();
}
}
@Override
public String toString() {
return MoreObjects.toStringHelper(FactoryProxy.class)
.add("key", key)
.add("provider", targetFactory)
.toString();
}
}

View file

@ -0,0 +1,44 @@
package com.google.inject.internal;
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
/**
* Lazily creates (and caches) values for keys. If creating the value fails (with errors), an
* exception is thrown on retrieval.
*/
public abstract class FailableCache<K, V> {
private final LoadingCache<K, Object> delegate = CacheBuilder.newBuilder().build(
new CacheLoader<K, Object>() {
public Object load(K key) {
Errors errors = new Errors();
V result = null;
try {
result = FailableCache.this.create(key, errors);
} catch (ErrorsException e) {
errors.merge(e.getErrors());
}
return errors.hasErrors() ? errors : result;
}
});
protected abstract V create(K key, Errors errors) throws ErrorsException;
public V get(K key, Errors errors) throws ErrorsException {
Object resultOrError = delegate.getUnchecked(key);
if (resultOrError instanceof Errors) {
errors.merge((Errors) resultOrError);
throw errors.toException();
} else {
@SuppressWarnings("unchecked") // create returned a non-error result, so this is safe
V result = (V) resultOrError;
return result;
}
}
boolean remove(K key) {
return delegate.asMap().remove(key) != null;
}
}

View file

@ -0,0 +1,160 @@
package com.google.inject.internal;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Binding;
import com.google.inject.Key;
import com.google.inject.Scope;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.ModuleAnnotatedMethodScannerBinding;
import com.google.inject.spi.ProvisionListenerBinding;
import com.google.inject.spi.ScopeBinding;
import com.google.inject.spi.TypeConverterBinding;
import com.google.inject.spi.TypeListenerBinding;
import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.google.common.base.Preconditions.checkNotNull;
final class InheritingState implements State {
private final State parent;
// Must be a linked hashmap in order to preserve order of bindings in Modules.
private final Map<Key<?>, Binding<?>> explicitBindingsMutable = Maps.newLinkedHashMap();
private final Map<Key<?>, Binding<?>> explicitBindings
= Collections.unmodifiableMap(explicitBindingsMutable);
private final Map<Class<? extends Annotation>, ScopeBinding> scopes = Maps.newHashMap();
private final List<TypeConverterBinding> converters = Lists.newArrayList();
private final List<TypeListenerBinding> typeListenerBindings = Lists.newArrayList();
private final List<ProvisionListenerBinding> provisionListenerBindings = Lists.newArrayList();
private final List<ModuleAnnotatedMethodScannerBinding> scannerBindings = Lists.newArrayList();
private final WeakKeySet blacklistedKeys;
private final Object lock;
InheritingState(State parent) {
this.parent = checkNotNull(parent, "parent");
this.lock = (parent == State.NONE) ? this : parent.lock();
this.blacklistedKeys = new WeakKeySet(lock);
}
public State parent() {
return parent;
}
@SuppressWarnings("unchecked") // we only put in BindingImpls that match their key types
public <T> BindingImpl<T> getExplicitBinding(Key<T> key) {
Binding<?> binding = explicitBindings.get(key);
return binding != null ? (BindingImpl<T>) binding : parent.getExplicitBinding(key);
}
public Map<Key<?>, Binding<?>> getExplicitBindingsThisLevel() {
return explicitBindings;
}
public void putBinding(Key<?> key, BindingImpl<?> binding) {
explicitBindingsMutable.put(key, binding);
}
public ScopeBinding getScopeBinding(Class<? extends Annotation> annotationType) {
ScopeBinding scopeBinding = scopes.get(annotationType);
return scopeBinding != null ? scopeBinding : parent.getScopeBinding(annotationType);
}
public void putScopeBinding(Class<? extends Annotation> annotationType, ScopeBinding scope) {
scopes.put(annotationType, scope);
}
public Iterable<TypeConverterBinding> getConvertersThisLevel() {
return converters;
}
public void addConverter(TypeConverterBinding typeConverterBinding) {
converters.add(typeConverterBinding);
}
public TypeConverterBinding getConverter(
String stringValue, TypeLiteral<?> type, Errors errors, Object source) {
TypeConverterBinding matchingConverter = null;
for (State s = this; s != State.NONE; s = s.parent()) {
for (TypeConverterBinding converter : s.getConvertersThisLevel()) {
if (converter.getTypeMatcher().matches(type)) {
if (matchingConverter != null) {
errors.ambiguousTypeConversion(stringValue, source, type, matchingConverter, converter);
}
matchingConverter = converter;
}
}
}
return matchingConverter;
}
public void addTypeListener(TypeListenerBinding listenerBinding) {
typeListenerBindings.add(listenerBinding);
}
public List<TypeListenerBinding> getTypeListenerBindings() {
List<TypeListenerBinding> parentBindings = parent.getTypeListenerBindings();
List<TypeListenerBinding> result =
Lists.newArrayListWithCapacity(parentBindings.size() + typeListenerBindings.size());
result.addAll(parentBindings);
result.addAll(typeListenerBindings);
return result;
}
public void addProvisionListener(ProvisionListenerBinding listenerBinding) {
provisionListenerBindings.add(listenerBinding);
}
public List<ProvisionListenerBinding> getProvisionListenerBindings() {
List<ProvisionListenerBinding> parentBindings = parent.getProvisionListenerBindings();
List<ProvisionListenerBinding> result =
Lists.newArrayListWithCapacity(parentBindings.size() + provisionListenerBindings.size());
result.addAll(parentBindings);
result.addAll(provisionListenerBindings);
return result;
}
public void addScanner(ModuleAnnotatedMethodScannerBinding scanner) {
scannerBindings.add(scanner);
}
public List<ModuleAnnotatedMethodScannerBinding> getScannerBindings() {
List<ModuleAnnotatedMethodScannerBinding> parentBindings = parent.getScannerBindings();
List<ModuleAnnotatedMethodScannerBinding> result =
Lists.newArrayListWithCapacity(parentBindings.size() + scannerBindings.size());
result.addAll(parentBindings);
result.addAll(scannerBindings);
return result;
}
public void blacklist(Key<?> key, State state, Object source) {
parent.blacklist(key, state, source);
blacklistedKeys.add(key, state, source);
}
public boolean isBlacklisted(Key<?> key) {
return blacklistedKeys.contains(key);
}
public Set<Object> getSourcesForBlacklistedKey(Key<?> key) {
return blacklistedKeys.getSources(key);
}
public Object lock() {
return lock;
}
public Map<Class<? extends Annotation>, Scope> getScopes() {
ImmutableMap.Builder<Class<? extends Annotation>, Scope> builder = ImmutableMap.builder();
for (Map.Entry<Class<? extends Annotation>, ScopeBinding> entry : scopes.entrySet()) {
builder.put(entry.getKey(), entry.getValue().getScope());
}
return builder.build();
}
}

View file

@ -0,0 +1,12 @@
package com.google.inject.internal;
/**
* Holds a reference that requires initialization to be performed before it can be used.
*/
interface Initializable<T> {
/**
* Ensures the reference is initialized, then returns it.
*/
T get(Errors errors) throws ErrorsException;
}

View file

@ -0,0 +1,20 @@
package com.google.inject.internal;
final class Initializables {
/**
* Returns an initializable for an instance that requires no initialization.
*/
static <T> Initializable<T> of(final T instance) {
return new Initializable<T>() {
public T get(Errors errors) throws ErrorsException {
return instance;
}
@Override
public String toString() {
return String.valueOf(instance);
}
};
}
}

View file

@ -0,0 +1,181 @@
package com.google.inject.internal;
import com.google.common.base.Preconditions;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Binding;
import com.google.inject.Key;
import com.google.inject.Stage;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.InjectionPoint;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CountDownLatch;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Manages and injects instances at injector-creation time. This is made more complicated by
* instances that request other instances while they're being injected. We overcome this by using
* {@link Initializable}, which attempts to perform injection before use.
*
*/
final class Initializer {
/**
* the only thread that we'll use to inject members.
*/
private final Thread creatingThread = Thread.currentThread();
/**
* zero means everything is injected.
*/
private final CountDownLatch ready = new CountDownLatch(1);
/**
* Maps from instances that need injection to the MembersInjector that will inject them.
*/
private final Map<Object, MembersInjectorImpl<?>> pendingMembersInjectors =
Maps.newIdentityHashMap();
/**
* Maps instances that need injection to a source that registered them
*/
private final Map<Object, InjectableReference<?>> pendingInjection = Maps.newIdentityHashMap();
/**
* Registers an instance for member injection when that step is performed.
*
* @param instance an instance that optionally has members to be injected (each annotated with
* @param binding the binding that caused this initializable to be created, if it exists.
* @param source the source location that this injection was requested
* @Inject).
*/
<T> Initializable<T> requestInjection(InjectorImpl injector, T instance, Binding<T> binding,
Object source, Set<InjectionPoint> injectionPoints) {
checkNotNull(source);
ProvisionListenerStackCallback<T> provisionCallback =
binding == null ? null : injector.provisionListenerStore.get(binding);
// short circuit if the object has no injections or listeners.
if (instance == null || (injectionPoints.isEmpty()
&& !injector.membersInjectorStore.hasTypeListeners()
&& (provisionCallback == null || !provisionCallback.hasListeners()))) {
return Initializables.of(instance);
}
InjectableReference<T> initializable = new InjectableReference<T>(
injector, instance, binding == null ? null : binding.getKey(), provisionCallback, source);
pendingInjection.put(instance, initializable);
return initializable;
}
/**
* Prepares member injectors for all injected instances. This prompts Guice to do static analysis
* on the injected instances.
*/
void validateOustandingInjections(Errors errors) {
for (InjectableReference<?> reference : pendingInjection.values()) {
try {
pendingMembersInjectors.put(reference.instance, reference.validate(errors));
} catch (ErrorsException e) {
errors.merge(e.getErrors());
}
}
}
/**
* Performs creation-time injections on all objects that require it. Whenever fulfilling an
* injection depends on another object that requires injection, we inject it first. If the two
* instances are codependent (directly or transitively), ordering of injection is arbitrary.
*/
void injectAll(final Errors errors) {
// loop over a defensive copy since ensureInjected() mutates the set. Unfortunately, that copy
// is made complicated by a bug in IBM's JDK, wherein entrySet().toArray(Object[]) doesn't work
for (InjectableReference<?> reference : Lists.newArrayList(pendingInjection.values())) {
try {
reference.get(errors);
} catch (ErrorsException e) {
errors.merge(e.getErrors());
}
}
if (!pendingInjection.isEmpty()) {
throw new AssertionError("Failed to satisfy " + pendingInjection);
}
ready.countDown();
}
private class InjectableReference<T> implements Initializable<T> {
private final InjectorImpl injector;
private final T instance;
private final Object source;
private final Key<T> key;
private final ProvisionListenerStackCallback<T> provisionCallback;
public InjectableReference(InjectorImpl injector, T instance, Key<T> key,
ProvisionListenerStackCallback<T> provisionCallback, Object source) {
this.injector = injector;
this.key = key; // possibly null!
this.provisionCallback = provisionCallback; // possibly null!
this.instance = checkNotNull(instance, "instance");
this.source = checkNotNull(source, "source");
}
public MembersInjectorImpl<T> validate(Errors errors) throws ErrorsException {
@SuppressWarnings("unchecked") // the type of 'T' is a TypeLiteral<T>
TypeLiteral<T> type = TypeLiteral.get((Class<T>) instance.getClass());
return injector.membersInjectorStore.get(type, errors.withSource(source));
}
/**
* Reentrant. If {@code instance} was registered for injection at injector-creation time, this
* method will ensure that all its members have been injected before returning.
*/
public T get(Errors errors) throws ErrorsException {
if (ready.getCount() == 0) {
return instance;
}
// just wait for everything to be injected by another thread
if (Thread.currentThread() != creatingThread) {
try {
ready.await();
return instance;
} catch (InterruptedException e) {
// Give up, since we don't know if our injection is ready
throw new RuntimeException(e);
}
}
// toInject needs injection, do it right away. we only do this once, even if it fails
if (pendingInjection.remove(instance) != null) {
// safe because we only insert a members injector for the appropriate instance
@SuppressWarnings("unchecked")
MembersInjectorImpl<T> membersInjector =
(MembersInjectorImpl<T>) pendingMembersInjectors.remove(instance);
Preconditions.checkState(membersInjector != null,
"No membersInjector available for instance: %s, from key: %s", instance, key);
// if in Stage.TOOL, we only want to inject & notify toolable injection points.
// (otherwise we'll inject all of them)
membersInjector.injectAndNotify(instance,
errors.withSource(source),
key,
provisionCallback,
source,
injector.options.stage == Stage.TOOL);
}
return instance;
}
@Override
public String toString() {
return instance.toString();
}
}
}

View file

@ -0,0 +1,119 @@
package com.google.inject.internal;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.inject.ConfigurationException;
import com.google.inject.Stage;
import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.InjectionRequest;
import com.google.inject.spi.StaticInjectionRequest;
import java.util.List;
import java.util.Set;
/**
* Handles {@code Binder.requestInjection} and {@code Binder.requestStaticInjection} commands.
*
*/
final class InjectionRequestProcessor extends AbstractProcessor {
private final List<StaticInjection> staticInjections = Lists.newArrayList();
private final Initializer initializer;
InjectionRequestProcessor(Errors errors, Initializer initializer) {
super(errors);
this.initializer = initializer;
}
@Override
public Boolean visit(StaticInjectionRequest request) {
staticInjections.add(new StaticInjection(injector, request));
return true;
}
@Override
public Boolean visit(InjectionRequest<?> request) {
Set<InjectionPoint> injectionPoints;
try {
injectionPoints = request.getInjectionPoints();
} catch (ConfigurationException e) {
errors.merge(e.getErrorMessages());
injectionPoints = e.getPartialValue();
}
initializer.requestInjection(
injector, request.getInstance(), null, request.getSource(), injectionPoints);
return true;
}
void validate() {
for (StaticInjection staticInjection : staticInjections) {
staticInjection.validate();
}
}
void injectMembers() {
/*
* TODO: If you request both a parent class and one of its
* subclasses, the parent class's static members will be
* injected twice.
*/
for (StaticInjection staticInjection : staticInjections) {
staticInjection.injectMembers();
}
}
/**
* A requested static injection.
*/
private class StaticInjection {
final InjectorImpl injector;
final Object source;
final StaticInjectionRequest request;
ImmutableList<SingleMemberInjector> memberInjectors;
public StaticInjection(InjectorImpl injector, StaticInjectionRequest request) {
this.injector = injector;
this.source = request.getSource();
this.request = request;
}
void validate() {
Errors errorsForMember = errors.withSource(source);
Set<InjectionPoint> injectionPoints;
try {
injectionPoints = request.getInjectionPoints();
} catch (ConfigurationException e) {
errorsForMember.merge(e.getErrorMessages());
injectionPoints = e.getPartialValue();
}
if (injectionPoints != null) {
memberInjectors = injector.membersInjectorStore.getInjectors(
injectionPoints, errorsForMember);
} else {
memberInjectors = ImmutableList.of();
}
errors.merge(errorsForMember);
}
void injectMembers() {
try {
injector.callInContext(new ContextualCallable<Void>() {
public Void call(InternalContext context) {
for (SingleMemberInjector memberInjector : memberInjectors) {
// Run injections if we're not in tool stage (ie, PRODUCTION or DEV),
// or if we are in tool stage and the injection point is toolable.
if (injector.options.stage != Stage.TOOL || memberInjector.getInjectionPoint().isToolable()) {
memberInjector.inject(errors, context, null);
}
}
return null;
}
});
} catch (ErrorsException e) {
throw new AssertionError();
}
}
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,71 @@
package com.google.inject.internal;
import com.google.inject.Stage;
import com.google.inject.internal.InjectorImpl.InjectorOptions;
import com.google.inject.spi.DisableCircularProxiesOption;
import com.google.inject.spi.RequireAtInjectOnConstructorsOption;
import com.google.inject.spi.RequireExactBindingAnnotationsOption;
import com.google.inject.spi.RequireExplicitBindingsOption;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
/**
* A processor to gather injector options.
*/
class InjectorOptionsProcessor extends AbstractProcessor {
private boolean disableCircularProxies = false;
private boolean jitDisabled = false;
private boolean atInjectRequired = false;
private boolean exactBindingAnnotationsRequired = false;
InjectorOptionsProcessor(Errors errors) {
super(errors);
}
@Override
public Boolean visit(DisableCircularProxiesOption option) {
disableCircularProxies = true;
return true;
}
@Override
public Boolean visit(RequireExplicitBindingsOption option) {
jitDisabled = true;
return true;
}
@Override
public Boolean visit(RequireAtInjectOnConstructorsOption option) {
atInjectRequired = true;
return true;
}
@Override
public Boolean visit(RequireExactBindingAnnotationsOption option) {
exactBindingAnnotationsRequired = true;
return true;
}
InjectorOptions getOptions(Stage stage, InjectorOptions parentOptions) {
checkNotNull(stage, "stage must be set");
if (parentOptions == null) {
return new InjectorOptions(
stage,
jitDisabled,
disableCircularProxies,
atInjectRequired,
exactBindingAnnotationsRequired);
} else {
checkState(stage == parentOptions.stage, "child & parent stage don't match");
return new InjectorOptions(
stage,
jitDisabled || parentOptions.jitDisabled,
disableCircularProxies || parentOptions.disableCircularProxies,
atInjectRequired || parentOptions.atInjectRequired,
exactBindingAnnotationsRequired || parentOptions.exactBindingAnnotationsRequired);
}
}
}

View file

@ -0,0 +1,296 @@
package com.google.inject.internal;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Lists;
import com.google.inject.Binder;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.Singleton;
import com.google.inject.Stage;
import com.google.inject.internal.InjectorImpl.InjectorOptions;
import com.google.inject.internal.util.SourceProvider;
import com.google.inject.internal.util.Stopwatch;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.Element;
import com.google.inject.spi.Elements;
import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.ModuleAnnotatedMethodScannerBinding;
import com.google.inject.spi.PrivateElements;
import com.google.inject.spi.ProvisionListenerBinding;
import com.google.inject.spi.TypeListenerBinding;
import java.util.List;
import static com.google.common.base.Preconditions.checkState;
import static com.google.inject.Scopes.SINGLETON;
/**
* A partially-initialized injector. See {@link InternalInjectorCreator}, which
* uses this to build a tree of injectors in batch.
*/
final class InjectorShell {
private final List<Element> elements;
private final InjectorImpl injector;
private InjectorShell(Builder builder, List<Element> elements, InjectorImpl injector) {
this.elements = elements;
this.injector = injector;
}
/**
* The Injector is a special case because we allow both parent and child injectors to both have
* a binding for that key.
*/
private static void bindInjector(InjectorImpl injector) {
Key<Injector> key = Key.get(Injector.class);
InjectorFactory injectorFactory = new InjectorFactory(injector);
injector.state.putBinding(key,
new ProviderInstanceBindingImpl<Injector>(injector, key, SourceProvider.UNKNOWN_SOURCE,
injectorFactory, Scoping.UNSCOPED, injectorFactory,
ImmutableSet.<InjectionPoint>of()));
}
/**
* The Logger is a special case because it knows the injection point of the injected member. It's
* the only binding that does this.
*/
/*private static void bindLogger(InjectorImpl injector) {
Key<Logger> key = Key.get(Logger.class);
LoggerFactory loggerFactory = new LoggerFactory();
injector.state.putBinding(key,
new ProviderInstanceBindingImpl<Logger>(injector, key,
SourceProvider.UNKNOWN_SOURCE, loggerFactory, Scoping.UNSCOPED,
loggerFactory, ImmutableSet.<InjectionPoint>of()));
}*/
private static void bindStage(InjectorImpl injector, Stage stage) {
Key<Stage> key = Key.get(Stage.class);
InstanceBindingImpl<Stage> stageBinding = new InstanceBindingImpl<Stage>(
injector,
key,
SourceProvider.UNKNOWN_SOURCE,
new ConstantFactory<Stage>(Initializables.of(stage)),
ImmutableSet.<InjectionPoint>of(),
stage);
injector.state.putBinding(key, stageBinding);
}
InjectorImpl getInjector() {
return injector;
}
List<Element> getElements() {
return elements;
}
static class Builder {
private final List<Element> elements = Lists.newArrayList();
private final List<Module> modules = Lists.newArrayList();
/**
* lazily constructed
*/
private State state;
private InjectorImpl parent;
private InjectorOptions options;
private Stage stage;
/**
* null unless this exists in a {@link Binder#newPrivateBinder private environment}
*/
private PrivateElementsImpl privateElements;
Builder stage(Stage stage) {
this.stage = stage;
return this;
}
Builder parent(InjectorImpl parent) {
this.parent = parent;
this.state = new InheritingState(parent.state);
this.options = parent.options;
this.stage = options.stage;
return this;
}
Builder privateElements(PrivateElements privateElements) {
this.privateElements = (PrivateElementsImpl) privateElements;
this.elements.addAll(privateElements.getElements());
return this;
}
void addModules(Iterable<? extends Module> modules) {
if (modules != null) {
for (Module module : modules) {
this.modules.add(module);
}
}
}
Stage getStage() {
return options.stage;
}
/**
* Synchronize on this before calling {@link #build}.
*/
Object lock() {
return getState().lock();
}
/**
* Creates and returns the injector shells for the current modules. Multiple shells will be
* returned if any modules contain {@link Binder#newPrivateBinder private environments}. The
* primary injector will be first in the returned list.
*/
List<InjectorShell> build(
Initializer initializer,
ProcessedBindingData bindingData,
Stopwatch stopwatch,
Errors errors) {
checkState(stage != null, "Stage not initialized");
checkState(privateElements == null || parent != null, "PrivateElements with no parent");
checkState(state != null, "no state. Did you remember to lock() ?");
// bind Singleton if this is a top-level injector
if (parent == null) {
modules.add(0, new RootModule());
} else {
modules.add(0, new InheritedScannersModule(parent.state));
}
elements.addAll(Elements.getElements(stage, modules));
// Look for injector-changing options
InjectorOptionsProcessor optionsProcessor = new InjectorOptionsProcessor(errors);
optionsProcessor.process(null, elements);
options = optionsProcessor.getOptions(stage, options);
InjectorImpl injector = new InjectorImpl(parent, state, options);
if (privateElements != null) {
privateElements.initInjector(injector);
}
// add default type converters if this is a top-level injector
if (parent == null) {
TypeConverterBindingProcessor.prepareBuiltInConverters(injector);
}
stopwatch.resetAndLog("Module execution");
new MessageProcessor(errors).process(injector, elements);
new ListenerBindingProcessor(errors).process(injector, elements);
List<TypeListenerBinding> typeListenerBindings = injector.state.getTypeListenerBindings();
injector.membersInjectorStore = new MembersInjectorStore(injector, typeListenerBindings);
List<ProvisionListenerBinding> provisionListenerBindings =
injector.state.getProvisionListenerBindings();
injector.provisionListenerStore =
new ProvisionListenerCallbackStore(provisionListenerBindings);
stopwatch.resetAndLog("TypeListeners & ProvisionListener creation");
new ScopeBindingProcessor(errors).process(injector, elements);
stopwatch.resetAndLog("Scopes creation");
new TypeConverterBindingProcessor(errors).process(injector, elements);
stopwatch.resetAndLog("Converters creation");
bindStage(injector, stage);
bindInjector(injector);
//bindLogger(injector);
// Process all normal bindings, then UntargettedBindings.
// This is necessary because UntargettedBindings can create JIT bindings
// and need all their other dependencies set up ahead of time.
new BindingProcessor(errors, initializer, bindingData).process(injector, elements);
new UntargettedBindingProcessor(errors, bindingData).process(injector, elements);
stopwatch.resetAndLog("Binding creation");
new ModuleAnnotatedMethodScannerProcessor(errors).process(injector, elements);
stopwatch.resetAndLog("Module annotated method scanners creation");
List<InjectorShell> injectorShells = Lists.newArrayList();
injectorShells.add(new InjectorShell(this, elements, injector));
// recursively build child shells
PrivateElementProcessor processor = new PrivateElementProcessor(errors);
processor.process(injector, elements);
for (Builder builder : processor.getInjectorShellBuilders()) {
injectorShells.addAll(builder.build(initializer, bindingData, stopwatch, errors));
}
stopwatch.resetAndLog("Private environment creation");
return injectorShells;
}
private State getState() {
if (state == null) {
state = new InheritingState(State.NONE);
}
return state;
}
}
private static class InjectorFactory implements InternalFactory<Injector>, Provider<Injector> {
private final Injector injector;
private InjectorFactory(Injector injector) {
this.injector = injector;
}
public Injector get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
throws ErrorsException {
return injector;
}
public Injector get() {
return injector;
}
public String toString() {
return "Provider<Injector>";
}
}
/*private static class LoggerFactory implements InternalFactory<Logger>, Provider<Logger> {
public Logger get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked) {
InjectionPoint injectionPoint = dependency.getInjectionPoint();
return injectionPoint == null
? Logger.getAnonymousLogger()
: Logger.getLogger(injectionPoint.getMember().getDeclaringClass().getName());
}
public Logger get() {
return Logger.getAnonymousLogger();
}
public String toString() {
return "Provider<Logger>";
}
}*/
private static class RootModule implements Module {
public void configure(Binder binder) {
binder = binder.withSource(SourceProvider.UNKNOWN_SOURCE);
binder.bindScope(Singleton.class, SINGLETON);
binder.bindScope(javax.inject.Singleton.class, SINGLETON);
}
}
private static class InheritedScannersModule implements Module {
private final State state;
InheritedScannersModule(State state) {
this.state = state;
}
public void configure(Binder binder) {
for (ModuleAnnotatedMethodScannerBinding binding : state.getScannerBindings()) {
binding.applyTo(binder);
}
}
}
}

View file

@ -0,0 +1,102 @@
package com.google.inject.internal;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Binder;
import com.google.inject.Key;
import com.google.inject.Provider;
import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.HasDependencies;
import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.InstanceBinding;
import com.google.inject.util.Providers;
import java.util.Set;
final class InstanceBindingImpl<T> extends BindingImpl<T> implements InstanceBinding<T> {
final T instance;
final Provider<T> provider;
final ImmutableSet<InjectionPoint> injectionPoints;
public InstanceBindingImpl(InjectorImpl injector, Key<T> key, Object source,
InternalFactory<? extends T> internalFactory, Set<InjectionPoint> injectionPoints,
T instance) {
super(injector, key, source, internalFactory, Scoping.EAGER_SINGLETON);
this.injectionPoints = ImmutableSet.copyOf(injectionPoints);
this.instance = instance;
this.provider = Providers.of(instance);
}
public InstanceBindingImpl(Object source, Key<T> key, Scoping scoping,
Set<InjectionPoint> injectionPoints, T instance) {
super(source, key, scoping);
this.injectionPoints = ImmutableSet.copyOf(injectionPoints);
this.instance = instance;
this.provider = Providers.of(instance);
}
@Override
public Provider<T> getProvider() {
return this.provider;
}
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
return visitor.visit(this);
}
public T getInstance() {
return instance;
}
public Set<InjectionPoint> getInjectionPoints() {
return injectionPoints;
}
public Set<Dependency<?>> getDependencies() {
return instance instanceof HasDependencies
? ImmutableSet.copyOf(((HasDependencies) instance).getDependencies())
: Dependency.forInjectionPoints(injectionPoints);
}
public BindingImpl<T> withScoping(Scoping scoping) {
return new InstanceBindingImpl<T>(getSource(), getKey(), scoping, injectionPoints, instance);
}
public BindingImpl<T> withKey(Key<T> key) {
return new InstanceBindingImpl<T>(getSource(), key, getScoping(), injectionPoints, instance);
}
public void applyTo(Binder binder) {
// instance bindings aren't scoped
binder.withSource(getSource()).bind(getKey()).toInstance(instance);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(InstanceBinding.class)
.add("key", getKey())
.add("source", getSource())
.add("instance", instance)
.toString();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof InstanceBindingImpl) {
InstanceBindingImpl<?> o = (InstanceBindingImpl<?>) obj;
return getKey().equals(o.getKey())
&& getScoping().equals(o.getScoping())
&& Objects.equal(instance, o.instance);
} else {
return false;
}
}
@Override
public int hashCode() {
return Objects.hashCode(getKey(), getScoping());
}
}

View file

@ -0,0 +1,136 @@
package com.google.inject.internal;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Maps;
import com.google.inject.Key;
import com.google.inject.internal.InjectorImpl.InjectorOptions;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.DependencyAndSource;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
/**
* Internal context. Used to coordinate injections and support circular
* dependencies.
*/
final class InternalContext {
private final InjectorOptions options;
/**
* Keeps track of the hierarchy of types needed during injection.
*/
private final DependencyStack state = new DependencyStack();
private Map<Object, ConstructionContext<?>> constructionContexts = Maps.newHashMap();
/**
* Keeps track of the type that is currently being requested for injection.
*/
private Dependency<?> dependency;
InternalContext(InjectorOptions options) {
this.options = options;
}
public InjectorOptions getInjectorOptions() {
return options;
}
@SuppressWarnings("unchecked")
public <T> ConstructionContext<T> getConstructionContext(Object key) {
ConstructionContext<T> constructionContext
= (ConstructionContext<T>) constructionContexts.get(key);
if (constructionContext == null) {
constructionContext = new ConstructionContext<T>();
constructionContexts.put(key, constructionContext);
}
return constructionContext;
}
public Dependency<?> getDependency() {
return dependency;
}
/**
* Sets the new current dependency & adds it to the state.
*/
public Dependency<?> pushDependency(Dependency<?> dependency, Object source) {
Dependency<?> previous = this.dependency;
this.dependency = dependency;
state.add(dependency, source);
return previous;
}
/**
* Pops the current state & sets the new dependency.
*/
public void popStateAndSetDependency(Dependency<?> newDependency) {
state.pop();
this.dependency = newDependency;
}
/**
* Adds to the state without setting the dependency.
*/
public void pushState(Key<?> key, Object source) {
state.add(key, source);
}
/**
* Pops from the state without setting a dependency.
*/
public void popState() {
state.pop();
}
/**
* Returns the current dependency chain (all the state).
*/
public List<DependencyAndSource> getDependencyChain() {
ImmutableList.Builder<DependencyAndSource> builder = ImmutableList.builder();
for (int i = 0; i < state.size(); i += 2) {
Object evenEntry = state.get(i);
Dependency<?> dependency;
if (evenEntry instanceof Key) {
dependency = Dependency.get((Key<?>) evenEntry);
} else {
dependency = (Dependency<?>) evenEntry;
}
builder.add(new DependencyAndSource(dependency, state.get(i + 1)));
}
return builder.build();
}
/**
* Keeps track of the hierarchy of types needed during injection.
*
* <p>This is a pairwise combination of dependencies and sources, with dependencies or keys on
* even indices, and sources on odd indices. This structure is to avoid the memory overhead of
* DependencyAndSource objects, which can add to several tens of megabytes in large applications.
*/
private static final class DependencyStack {
private Object[] elements = new Object[16];
private int size = 0;
public void add(Object dependencyOrKey, Object source) {
if (elements.length < size + 2) {
elements = Arrays.copyOf(elements, (elements.length * 3) / 2 + 2);
}
elements[size++] = dependencyOrKey;
elements[size++] = source;
}
public void pop() {
elements[--size] = null;
elements[--size] = null;
}
public Object get(int i) {
return elements[i];
}
public int size() {
return size;
}
}
}

View file

@ -0,0 +1,20 @@
package com.google.inject.internal;
import com.google.inject.spi.Dependency;
/**
* Creates objects which will be injected.
*/
interface InternalFactory<T> {
/**
* Creates an object to be injected.
*
* @param context of this injection
* @param linked true if getting as a result of a linked binding
* @return instance to be injected
* @throws com.google.inject.internal.ErrorsException if a value cannot be provided
*/
T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
throws ErrorsException;
}

View file

@ -0,0 +1,45 @@
package com.google.inject.internal;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.ProviderInstanceBinding;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Adapts {@link ProviderInstanceBinding} providers, ensuring circular proxies
* fail (or proxy) properly.
*/
final class InternalFactoryToInitializableAdapter<T> extends ProviderInternalFactory<T> {
private final ProvisionListenerStackCallback<T> provisionCallback;
private final Initializable<? extends javax.inject.Provider<? extends T>> initializable;
public InternalFactoryToInitializableAdapter(
Initializable<? extends javax.inject.Provider<? extends T>> initializable,
Object source, ProvisionListenerStackCallback<T> provisionCallback) {
super(source);
this.provisionCallback = checkNotNull(provisionCallback, "provisionCallback");
this.initializable = checkNotNull(initializable, "provider");
}
public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
throws ErrorsException {
return circularGet(initializable.get(errors), errors, context, dependency,
provisionCallback);
}
@Override
protected T provision(javax.inject.Provider<? extends T> provider, Errors errors,
Dependency<?> dependency, ConstructionContext<T> constructionContext) throws ErrorsException {
try {
return super.provision(provider, errors, dependency, constructionContext);
} catch (RuntimeException userException) {
throw errors.withSource(source).errorInProvider(userException).toException();
}
}
@Override
public String toString() {
return initializable.toString();
}
}

View file

@ -0,0 +1,32 @@
package com.google.inject.internal;
import com.google.inject.Provider;
import com.google.inject.spi.Dependency;
import static com.google.common.base.Preconditions.checkNotNull;
final class InternalFactoryToProviderAdapter<T> implements InternalFactory<T> {
private final Provider<? extends T> provider;
private final Object source;
public InternalFactoryToProviderAdapter(Provider<? extends T> provider, Object source) {
this.provider = checkNotNull(provider, "provider");
this.source = checkNotNull(source, "source");
}
public T get(Errors errors, InternalContext context, Dependency<?> dependency, boolean linked)
throws ErrorsException {
// TODO(sameb): Does this need to push state into the context?
try {
return errors.checkForNull(provider.get(), source, dependency);
} catch (RuntimeException userException) {
throw errors.withSource(source).errorInProvider(userException).toException();
}
}
@Override
public String toString() {
return provider.toString();
}
}

View file

@ -0,0 +1,132 @@
package com.google.inject.internal;
import java.security.AccessController;
import java.security.PrivilegedAction;
/**
* Contains flags for Guice.
*/
public class InternalFlags {
private static final IncludeStackTraceOption INCLUDE_STACK_TRACES
= parseIncludeStackTraceOption();
private static final CustomClassLoadingOption CUSTOM_CLASS_LOADING
= parseCustomClassLoadingOption();
private static final NullableProvidesOption NULLABLE_PROVIDES
= parseNullableProvidesOption(NullableProvidesOption.ERROR);
public static IncludeStackTraceOption getIncludeStackTraceOption() {
return INCLUDE_STACK_TRACES;
}
public static CustomClassLoadingOption getCustomClassLoadingOption() {
return CUSTOM_CLASS_LOADING;
}
public static NullableProvidesOption getNullableProvidesOption() {
return NULLABLE_PROVIDES;
}
private static IncludeStackTraceOption parseIncludeStackTraceOption() {
return getSystemOption("guice_include_stack_traces",
IncludeStackTraceOption.ONLY_FOR_DECLARING_SOURCE);
}
private static CustomClassLoadingOption parseCustomClassLoadingOption() {
return getSystemOption("guice_custom_class_loading",
CustomClassLoadingOption.BRIDGE, CustomClassLoadingOption.OFF);
}
private static NullableProvidesOption parseNullableProvidesOption(
NullableProvidesOption defaultValue) {
return getSystemOption("guice_check_nullable_provides_params", defaultValue);
}
/**
* Gets the system option indicated by the specified key; runs as a privileged action.
*
* @param name of the system option
* @param defaultValue if the option is not set
* @return value of the option, defaultValue if not set
*/
private static <T extends Enum<T>> T getSystemOption(final String name, T defaultValue) {
return getSystemOption(name, defaultValue, defaultValue);
}
/**
* Gets the system option indicated by the specified key; runs as a privileged action.
*
* @param name of the system option
* @param defaultValue if the option is not set
* @param secureValue if the security manager disallows access to the option
* @return value of the option, defaultValue if not set, secureValue if no access
*/
private static <T extends Enum<T>> T getSystemOption(final String name, T defaultValue,
T secureValue) {
Class<T> enumType = defaultValue.getDeclaringClass();
String value = null;
try {
value = AccessController.doPrivileged(new PrivilegedAction<String>() {
public String run() {
return System.getProperty(name);
}
});
return (value != null && value.length() > 0) ? Enum.valueOf(enumType, value) : defaultValue;
} catch (SecurityException e) {
return secureValue;
} catch (IllegalArgumentException e) {
//logger.warning(value + " is not a valid flag value for " + name + ". "
// + " Values must be one of " + Arrays.asList(enumType.getEnumConstants()));
return defaultValue;
}
}
/**
* The options for Guice stack trace collection.
*/
public enum IncludeStackTraceOption {
/**
* No stack trace collection
*/
OFF,
/**
* Minimum stack trace collection (Default)
*/
ONLY_FOR_DECLARING_SOURCE,
/**
* Full stack trace for everything
*/
COMPLETE
}
/**
* The options for Guice custom class loading.
*/
public enum CustomClassLoadingOption {
/**
* No custom class loading
*/
OFF,
/**
* Automatically bridge between class loaders (Default)
*/
BRIDGE
}
public enum NullableProvidesOption {
/**
* Ignore null parameters to @Provides methods.
*/
IGNORE,
/**
* Warn if null parameters are passed to non-@Nullable parameters of provides methods.
*/
WARN,
/**
* Error if null parameters are passed to non-@Nullable parameters of provides parameters
*/
ERROR
}
}

View file

@ -0,0 +1,308 @@
package com.google.inject.internal;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.inject.Binding;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.MembersInjector;
import com.google.inject.Module;
import com.google.inject.Provider;
import com.google.inject.Scope;
import com.google.inject.Stage;
import com.google.inject.TypeLiteral;
import com.google.inject.internal.util.Stopwatch;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.TypeConverterBinding;
import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Set;
/**
* Builds a tree of injectors. This is a primary injector, plus child injectors needed for each
* {@code Binder.newPrivateBinder() private environment}. The primary injector is not necessarily a
* top-level injector.
*
* <p>Injector construction happens in two phases.
* <ol>
* <li>Static building. In this phase, we interpret commands, create bindings, and inspect
* dependencies. During this phase, we hold a lock to ensure consistency with parent injectors.
* No user code is executed in this phase.</li>
* <li>Dynamic injection. In this phase, we call user code. We inject members that requested
* injection. This may require user's objects be created and their providers be called. And we
* create eager singletons. In this phase, user code may have started other threads. This phase
* is not executed for injectors created using {@link Stage#TOOL the tool stage}</li>
* </ol>
*
*/
public final class InternalInjectorCreator {
private final Stopwatch stopwatch = new Stopwatch();
private final Errors errors = new Errors();
private final Initializer initializer = new Initializer();
private final ProcessedBindingData bindingData;
private final InjectionRequestProcessor injectionRequestProcessor;
private final InjectorShell.Builder shellBuilder = new InjectorShell.Builder();
private List<InjectorShell> shells;
public InternalInjectorCreator() {
injectionRequestProcessor = new InjectionRequestProcessor(errors, initializer);
bindingData = new ProcessedBindingData();
}
public InternalInjectorCreator stage(Stage stage) {
shellBuilder.stage(stage);
return this;
}
/**
* Sets the parent of the injector to-be-constructed. As a side effect, this sets this injector's
* stage to the stage of {@code parent}.
*/
public InternalInjectorCreator parentInjector(InjectorImpl parent) {
shellBuilder.parent(parent);
return this;
}
public InternalInjectorCreator addModules(Iterable<? extends Module> modules) {
shellBuilder.addModules(modules);
return this;
}
public Injector build() {
// Synchronize while we're building up the bindings and other injector state. This ensures that
// the JIT bindings in the parent injector don't change while we're being built
synchronized (shellBuilder.lock()) {
shells = shellBuilder.build(initializer, bindingData, stopwatch, errors);
stopwatch.resetAndLog("Injector construction");
initializeStatically();
}
injectDynamically();
if (shellBuilder.getStage() == Stage.TOOL) {
// wrap the primaryInjector in a ToolStageInjector
// to prevent non-tool-friendy methods from being called.
return new ToolStageInjector(primaryInjector());
} else {
return primaryInjector();
}
}
/**
* Initialize and validate everything.
*/
private void initializeStatically() {
bindingData.initializeBindings();
stopwatch.resetAndLog("Binding initialization");
for (InjectorShell shell : shells) {
shell.getInjector().index();
}
stopwatch.resetAndLog("Binding indexing");
injectionRequestProcessor.process(shells);
stopwatch.resetAndLog("Collecting injection requests");
bindingData.runCreationListeners(errors);
stopwatch.resetAndLog("Binding validation");
injectionRequestProcessor.validate();
stopwatch.resetAndLog("Static validation");
initializer.validateOustandingInjections(errors);
stopwatch.resetAndLog("Instance member validation");
new LookupProcessor(errors).process(shells);
for (InjectorShell shell : shells) {
((DeferredLookups) shell.getInjector().lookups).initialize(errors);
}
stopwatch.resetAndLog("Provider verification");
for (InjectorShell shell : shells) {
if (!shell.getElements().isEmpty()) {
throw new AssertionError("Failed to execute " + shell.getElements());
}
}
errors.throwCreationExceptionIfErrorsExist();
}
/**
* Returns the injector being constructed. This is not necessarily the root injector.
*/
private Injector primaryInjector() {
return shells.get(0).getInjector();
}
/**
* Inject everything that can be injected. This method is intentionally not synchronized. If we
* locked while injecting members (ie. running user code), things would deadlock should the user
* code build a just-in-time binding from another thread.
*/
private void injectDynamically() {
injectionRequestProcessor.injectMembers();
stopwatch.resetAndLog("Static member injection");
initializer.injectAll(errors);
stopwatch.resetAndLog("Instance injection");
errors.throwCreationExceptionIfErrorsExist();
if (shellBuilder.getStage() != Stage.TOOL) {
for (InjectorShell shell : shells) {
loadEagerSingletons(shell.getInjector(), shellBuilder.getStage(), errors);
}
stopwatch.resetAndLog("Preloading singletons");
}
errors.throwCreationExceptionIfErrorsExist();
}
/**
* Loads eager singletons, or all singletons if we're in Stage.PRODUCTION. Bindings discovered
* while we're binding these singletons are not be eager.
*/
void loadEagerSingletons(InjectorImpl injector, Stage stage, final Errors errors) {
@SuppressWarnings("unchecked") // casting Collection<Binding> to Collection<BindingImpl> is safe
Iterable<BindingImpl<?>> candidateBindings = ImmutableList.copyOf(Iterables.concat(
(Collection) injector.state.getExplicitBindingsThisLevel().values(),
injector.jitBindings.values()));
for (final BindingImpl<?> binding : candidateBindings) {
if (isEagerSingleton(injector, binding, stage)) {
try {
injector.callInContext(new ContextualCallable<Void>() {
Dependency<?> dependency = Dependency.get(binding.getKey());
public Void call(InternalContext context) {
Dependency previous = context.pushDependency(dependency, binding.getSource());
Errors errorsForBinding = errors.withSource(dependency);
try {
binding.getInternalFactory().get(errorsForBinding, context, dependency, false);
} catch (ErrorsException e) {
errorsForBinding.merge(e.getErrors());
} finally {
context.popStateAndSetDependency(previous);
}
return null;
}
});
} catch (ErrorsException e) {
throw new AssertionError();
}
}
}
}
private boolean isEagerSingleton(InjectorImpl injector, BindingImpl<?> binding, Stage stage) {
if (binding.getScoping().isEagerSingleton(stage)) {
return true;
}
// handle a corner case where a child injector links to a binding in a parent injector, and
// that binding is singleton. We won't catch this otherwise because we only iterate the child's
// bindings.
if (binding instanceof LinkedBindingImpl) {
Key<?> linkedBinding = ((LinkedBindingImpl<?>) binding).getLinkedKey();
return isEagerSingleton(injector, injector.getBinding(linkedBinding), stage);
}
return false;
}
/**
* {@link Injector} exposed to users in {@link Stage#TOOL}.
*/
static class ToolStageInjector implements Injector {
private final Injector delegateInjector;
ToolStageInjector(Injector delegateInjector) {
this.delegateInjector = delegateInjector;
}
public void injectMembers(Object o) {
throw new UnsupportedOperationException(
"Injector.injectMembers(Object) is not supported in Stage.TOOL");
}
public Map<Key<?>, Binding<?>> getBindings() {
return this.delegateInjector.getBindings();
}
public Map<Key<?>, Binding<?>> getAllBindings() {
return this.delegateInjector.getAllBindings();
}
public <T> Binding<T> getBinding(Key<T> key) {
return this.delegateInjector.getBinding(key);
}
public <T> Binding<T> getBinding(Class<T> type) {
return this.delegateInjector.getBinding(type);
}
public <T> Binding<T> getExistingBinding(Key<T> key) {
return this.delegateInjector.getExistingBinding(key);
}
public <T> List<Binding<T>> findBindingsByType(TypeLiteral<T> type) {
return this.delegateInjector.findBindingsByType(type);
}
public Injector getParent() {
return delegateInjector.getParent();
}
public Injector createChildInjector(Iterable<? extends Module> modules) {
return delegateInjector.createChildInjector(modules);
}
public Injector createChildInjector(Module... modules) {
return delegateInjector.createChildInjector(modules);
}
public Map<Class<? extends Annotation>, Scope> getScopeBindings() {
return delegateInjector.getScopeBindings();
}
public Set<TypeConverterBinding> getTypeConverterBindings() {
return delegateInjector.getTypeConverterBindings();
}
public <T> Provider<T> getProvider(Key<T> key) {
throw new UnsupportedOperationException(
"Injector.getProvider(Key<T>) is not supported in Stage.TOOL");
}
public <T> Provider<T> getProvider(Class<T> type) {
throw new UnsupportedOperationException(
"Injector.getProvider(Class<T>) is not supported in Stage.TOOL");
}
public <T> MembersInjector<T> getMembersInjector(TypeLiteral<T> typeLiteral) {
throw new UnsupportedOperationException(
"Injector.getMembersInjector(TypeLiteral<T>) is not supported in Stage.TOOL");
}
public <T> MembersInjector<T> getMembersInjector(Class<T> type) {
throw new UnsupportedOperationException(
"Injector.getMembersInjector(Class<T>) is not supported in Stage.TOOL");
}
public <T> T getInstance(Key<T> key) {
throw new UnsupportedOperationException(
"Injector.getInstance(Key<T>) is not supported in Stage.TOOL");
}
public <T> T getInstance(Class<T> type) {
throw new UnsupportedOperationException(
"Injector.getInstance(Class<T>) is not supported in Stage.TOOL");
}
}
}

View file

@ -0,0 +1,81 @@
package com.google.inject.internal;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Binder;
import com.google.inject.Key;
import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.HasDependencies;
import com.google.inject.spi.LinkedKeyBinding;
import java.util.Set;
public final class LinkedBindingImpl<T> extends BindingImpl<T> implements LinkedKeyBinding<T>, HasDependencies {
final Key<? extends T> targetKey;
public LinkedBindingImpl(InjectorImpl injector, Key<T> key, Object source,
InternalFactory<? extends T> internalFactory, Scoping scoping,
Key<? extends T> targetKey) {
super(injector, key, source, internalFactory, scoping);
this.targetKey = targetKey;
}
public LinkedBindingImpl(Object source, Key<T> key, Scoping scoping, Key<? extends T> targetKey) {
super(source, key, scoping);
this.targetKey = targetKey;
}
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
return visitor.visit(this);
}
public Key<? extends T> getLinkedKey() {
return targetKey;
}
public Set<Dependency<?>> getDependencies() {
return ImmutableSet.<Dependency<?>>of(Dependency.get(targetKey));
}
public BindingImpl<T> withScoping(Scoping scoping) {
return new LinkedBindingImpl<T>(getSource(), getKey(), scoping, targetKey);
}
public BindingImpl<T> withKey(Key<T> key) {
return new LinkedBindingImpl<T>(getSource(), key, getScoping(), targetKey);
}
public void applyTo(Binder binder) {
getScoping().applyTo(binder.withSource(getSource()).bind(getKey()).to(getLinkedKey()));
}
@Override
public String toString() {
return MoreObjects.toStringHelper(LinkedKeyBinding.class)
.add("key", getKey())
.add("source", getSource())
.add("scope", getScoping())
.add("target", targetKey)
.toString();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof LinkedBindingImpl) {
LinkedBindingImpl<?> o = (LinkedBindingImpl<?>) obj;
return getKey().equals(o.getKey())
&& getScoping().equals(o.getScoping())
&& Objects.equal(targetKey, o.targetKey);
} else {
return false;
}
}
@Override
public int hashCode() {
return Objects.hashCode(getKey(), getScoping(), targetKey);
}
}

View file

@ -0,0 +1,108 @@
package com.google.inject.internal;
import com.google.common.base.MoreObjects;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Binder;
import com.google.inject.Key;
import com.google.inject.spi.BindingTargetVisitor;
import com.google.inject.spi.Dependency;
import com.google.inject.spi.HasDependencies;
import com.google.inject.spi.ProviderKeyBinding;
import java.util.Set;
final class LinkedProviderBindingImpl<T>
extends BindingImpl<T> implements ProviderKeyBinding<T>, HasDependencies, DelayedInitialize {
final Key<? extends javax.inject.Provider<? extends T>> providerKey;
final DelayedInitialize delayedInitializer;
private LinkedProviderBindingImpl(InjectorImpl injector, Key<T> key, Object source,
InternalFactory<? extends T> internalFactory, Scoping scoping,
Key<? extends javax.inject.Provider<? extends T>> providerKey,
DelayedInitialize delayedInitializer) {
super(injector, key, source, internalFactory, scoping);
this.providerKey = providerKey;
this.delayedInitializer = delayedInitializer;
}
public LinkedProviderBindingImpl(InjectorImpl injector, Key<T> key, Object source,
InternalFactory<? extends T> internalFactory, Scoping scoping,
Key<? extends javax.inject.Provider<? extends T>> providerKey) {
this(injector, key, source, internalFactory, scoping, providerKey, null);
}
LinkedProviderBindingImpl(Object source, Key<T> key, Scoping scoping,
Key<? extends javax.inject.Provider<? extends T>> providerKey) {
super(source, key, scoping);
this.providerKey = providerKey;
this.delayedInitializer = null;
}
static <T> LinkedProviderBindingImpl<T> createWithInitializer(InjectorImpl injector, Key<T> key,
Object source, InternalFactory<? extends T> internalFactory, Scoping scoping,
Key<? extends javax.inject.Provider<? extends T>> providerKey,
DelayedInitialize delayedInitializer) {
return new LinkedProviderBindingImpl<T>(injector, key, source, internalFactory, scoping,
providerKey, delayedInitializer);
}
public <V> V acceptTargetVisitor(BindingTargetVisitor<? super T, V> visitor) {
return visitor.visit(this);
}
public Key<? extends javax.inject.Provider<? extends T>> getProviderKey() {
return providerKey;
}
public void initialize(InjectorImpl injector, Errors errors) throws ErrorsException {
if (delayedInitializer != null) {
delayedInitializer.initialize(injector, errors);
}
}
public Set<Dependency<?>> getDependencies() {
return ImmutableSet.<Dependency<?>>of(Dependency.get(providerKey));
}
public BindingImpl<T> withScoping(Scoping scoping) {
return new LinkedProviderBindingImpl<T>(getSource(), getKey(), scoping, providerKey);
}
public BindingImpl<T> withKey(Key<T> key) {
return new LinkedProviderBindingImpl<T>(getSource(), key, getScoping(), providerKey);
}
public void applyTo(Binder binder) {
getScoping().applyTo(binder.withSource(getSource())
.bind(getKey()).toProvider(getProviderKey()));
}
@Override
public String toString() {
return MoreObjects.toStringHelper(ProviderKeyBinding.class)
.add("key", getKey())
.add("source", getSource())
.add("scope", getScoping())
.add("provider", providerKey)
.toString();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof LinkedProviderBindingImpl) {
LinkedProviderBindingImpl<?> o = (LinkedProviderBindingImpl<?>) obj;
return getKey().equals(o.getKey())
&& getScoping().equals(o.getScoping())
&& Objects.equal(providerKey, o.providerKey);
} else {
return false;
}
}
@Override
public int hashCode() {
return Objects.hashCode(getKey(), getScoping(), providerKey);
}
}

View file

@ -0,0 +1,26 @@
package com.google.inject.internal;
import com.google.inject.spi.ProvisionListenerBinding;
import com.google.inject.spi.TypeListenerBinding;
/**
* Handles {@code Binder#bindListener} commands.
*/
final class ListenerBindingProcessor extends AbstractProcessor {
ListenerBindingProcessor(Errors errors) {
super(errors);
}
@Override
public Boolean visit(TypeListenerBinding binding) {
injector.state.addTypeListener(binding);
return true;
}
@Override
public Boolean visit(ProvisionListenerBinding binding) {
injector.state.addProvisionListener(binding);
return true;
}
}

View file

@ -0,0 +1,42 @@
package com.google.inject.internal;
import com.google.inject.MembersInjector;
import com.google.inject.Provider;
import com.google.inject.spi.MembersInjectorLookup;
import com.google.inject.spi.ProviderLookup;
/**
* Handles {@code Binder.getProvider} and {@code Binder.getMembersInjector(TypeLiteral)} commands.
*/
final class LookupProcessor extends AbstractProcessor {
LookupProcessor(Errors errors) {
super(errors);
}
@Override
public <T> Boolean visit(MembersInjectorLookup<T> lookup) {
try {
MembersInjector<T> membersInjector
= injector.membersInjectorStore.get(lookup.getType(), errors);
lookup.initializeDelegate(membersInjector);
} catch (ErrorsException e) {
errors.merge(e.getErrors()); // TODO: source
}
return true;
}
@Override
public <T> Boolean visit(ProviderLookup<T> lookup) {
// ensure the provider can be created
try {
Provider<T> provider = injector.getProviderOrThrow(lookup.getDependency(), errors);
lookup.initializeDelegate(provider);
} catch (ErrorsException e) {
errors.merge(e.getErrors()); // TODO: source
}
return true;
}
}

View file

@ -0,0 +1,17 @@
package com.google.inject.internal;
import com.google.inject.Key;
import com.google.inject.MembersInjector;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
/**
* Accessors for providers and members injectors. The returned values will not be functional until
* the injector has been created.
*/
interface Lookups {
<T> Provider<T> getProvider(Key<T> key);
<T> MembersInjector<T> getMembersInjector(TypeLiteral<T> type);
}

View file

@ -0,0 +1,138 @@
package com.google.inject.internal;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.inject.Key;
import com.google.inject.MembersInjector;
import com.google.inject.TypeLiteral;
import com.google.inject.internal.ProvisionListenerStackCallback.ProvisionCallback;
import com.google.inject.spi.InjectionListener;
import com.google.inject.spi.InjectionPoint;
/**
* Injects members of instances of a given type.
*/
final class MembersInjectorImpl<T> implements MembersInjector<T> {
private final TypeLiteral<T> typeLiteral;
private final InjectorImpl injector;
private final ImmutableList<SingleMemberInjector> memberInjectors;
private final ImmutableSet<MembersInjector<? super T>> userMembersInjectors;
private final ImmutableSet<InjectionListener<? super T>> injectionListeners;
MembersInjectorImpl(InjectorImpl injector, TypeLiteral<T> typeLiteral,
EncounterImpl<T> encounter, ImmutableList<SingleMemberInjector> memberInjectors) {
this.injector = injector;
this.typeLiteral = typeLiteral;
this.memberInjectors = memberInjectors;
this.userMembersInjectors = encounter.getMembersInjectors();
this.injectionListeners = encounter.getInjectionListeners();
}
public ImmutableList<SingleMemberInjector> getMemberInjectors() {
return memberInjectors;
}
public void injectMembers(T instance) {
Errors errors = new Errors(typeLiteral);
try {
injectAndNotify(instance, errors, null, null, typeLiteral, false);
} catch (ErrorsException e) {
errors.merge(e.getErrors());
}
errors.throwProvisionExceptionIfErrorsExist();
}
void injectAndNotify(final T instance,
final Errors errors,
final Key<T> key, // possibly null!
final ProvisionListenerStackCallback<T> provisionCallback, // possibly null!
final Object source,
final boolean toolableOnly) throws ErrorsException {
if (instance == null) {
return;
}
injector.callInContext(new ContextualCallable<Void>() {
@Override
public Void call(final InternalContext context) throws ErrorsException {
context.pushState(key, source);
try {
if (provisionCallback != null && provisionCallback.hasListeners()) {
provisionCallback.provision(errors, context, new ProvisionCallback<T>() {
@Override
public T call() {
injectMembers(instance, errors, context, toolableOnly);
return instance;
}
});
} else {
injectMembers(instance, errors, context, toolableOnly);
}
} finally {
context.popState();
}
return null;
}
});
// TODO: We *could* notify listeners too here,
// but it's not clear if we want to. There's no way to know
// if a MembersInjector from the usersMemberInjector list wants
// toolable injections, so do we really want to notify
// about injection? (We could take a strategy of only notifying
// if atleast one InjectionPoint was toolable, in which case
// the above callInContext could return 'true' if it injected
// anything.)
if (!toolableOnly) {
notifyListeners(instance, errors);
}
}
void notifyListeners(T instance, Errors errors) throws ErrorsException {
int numErrorsBefore = errors.size();
for (InjectionListener<? super T> injectionListener : injectionListeners) {
try {
injectionListener.afterInjection(instance);
} catch (RuntimeException e) {
errors.errorNotifyingInjectionListener(injectionListener, typeLiteral, e);
}
}
errors.throwIfNewErrors(numErrorsBefore);
}
void injectMembers(T t, Errors errors, InternalContext context, boolean toolableOnly) {
// optimization: use manual for/each to save allocating an iterator here
for (int i = 0, size = memberInjectors.size(); i < size; i++) {
SingleMemberInjector injector = memberInjectors.get(i);
if (!toolableOnly || injector.getInjectionPoint().isToolable()) {
injector.inject(errors, context, t);
}
}
// TODO: There's no way to know if a user's MembersInjector wants toolable injections.
if (!toolableOnly) {
for (MembersInjector<? super T> userMembersInjector : userMembersInjectors) {
try {
userMembersInjector.injectMembers(t);
} catch (RuntimeException e) {
errors.errorInUserInjector(userMembersInjector, typeLiteral, e);
}
}
}
}
@Override
public String toString() {
return "MembersInjector<" + typeLiteral + ">";
}
public ImmutableSet<InjectionPoint> getInjectionPoints() {
ImmutableSet.Builder<InjectionPoint> builder = ImmutableSet.builder();
for (SingleMemberInjector memberInjector : memberInjectors) {
builder.add(memberInjector.getInjectionPoint());
}
return builder.build();
}
}

View file

@ -0,0 +1,124 @@
package com.google.inject.internal;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.inject.ConfigurationException;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.InjectionPoint;
import com.google.inject.spi.TypeListener;
import com.google.inject.spi.TypeListenerBinding;
import java.lang.reflect.Field;
import java.util.List;
import java.util.Set;
/**
* Members injectors by type.
*/
final class MembersInjectorStore {
private final InjectorImpl injector;
private final ImmutableList<TypeListenerBinding> typeListenerBindings;
private final FailableCache<TypeLiteral<?>, MembersInjectorImpl<?>> cache
= new FailableCache<TypeLiteral<?>, MembersInjectorImpl<?>>() {
@Override
protected MembersInjectorImpl<?> create(TypeLiteral<?> type, Errors errors)
throws ErrorsException {
return createWithListeners(type, errors);
}
};
MembersInjectorStore(InjectorImpl injector,
List<TypeListenerBinding> typeListenerBindings) {
this.injector = injector;
this.typeListenerBindings = ImmutableList.copyOf(typeListenerBindings);
}
/**
* Returns true if any type listeners are installed. Other code may take shortcuts when there
* aren't any type listeners.
*/
public boolean hasTypeListeners() {
return !typeListenerBindings.isEmpty();
}
/**
* Returns a new complete members injector with injection listeners registered.
*/
@SuppressWarnings("unchecked") // the MembersInjector type always agrees with the passed type
public <T> MembersInjectorImpl<T> get(TypeLiteral<T> key, Errors errors) throws ErrorsException {
return (MembersInjectorImpl<T>) cache.get(key, errors);
}
/**
* Purges a type literal from the cache. Use this only if the type is not actually valid for
* binding and needs to be purged. (See issue 319 and
* ImplicitBindingTest#testCircularJitBindingsLeaveNoResidue and
* #testInstancesRequestingProvidersForThemselvesWithChildInjectors for examples of when this is
* necessary.)
*
* Returns true if the type was stored in the cache, false otherwise.
*/
boolean remove(TypeLiteral<?> type) {
return cache.remove(type);
}
/**
* Creates a new members injector and attaches both injection listeners and method aspects.
*/
private <T> MembersInjectorImpl<T> createWithListeners(TypeLiteral<T> type, Errors errors)
throws ErrorsException {
int numErrorsBefore = errors.size();
Set<InjectionPoint> injectionPoints;
try {
injectionPoints = InjectionPoint.forInstanceMethodsAndFields(type);
} catch (ConfigurationException e) {
errors.merge(e.getErrorMessages());
injectionPoints = e.getPartialValue();
}
ImmutableList<SingleMemberInjector> injectors = getInjectors(injectionPoints, errors);
errors.throwIfNewErrors(numErrorsBefore);
EncounterImpl<T> encounter = new EncounterImpl<T>(errors, injector.lookups);
Set<TypeListener> alreadySeenListeners = Sets.newHashSet();
for (TypeListenerBinding binding : typeListenerBindings) {
TypeListener typeListener = binding.getListener();
if (!alreadySeenListeners.contains(typeListener) && binding.getTypeMatcher().matches(type)) {
alreadySeenListeners.add(typeListener);
try {
typeListener.hear(type, encounter);
} catch (RuntimeException e) {
errors.errorNotifyingTypeListener(binding, type, e);
}
}
}
encounter.invalidate();
errors.throwIfNewErrors(numErrorsBefore);
return new MembersInjectorImpl<T>(injector, type, encounter, injectors);
}
/**
* Returns the injectors for the specified injection points.
*/
ImmutableList<SingleMemberInjector> getInjectors(
Set<InjectionPoint> injectionPoints, Errors errors) {
List<SingleMemberInjector> injectors = Lists.newArrayList();
for (InjectionPoint injectionPoint : injectionPoints) {
try {
Errors errorsForMember = injectionPoint.isOptional()
? new Errors(injectionPoint)
: errors.withSource(injectionPoint);
SingleMemberInjector injector = injectionPoint.getMember() instanceof Field
? new SingleFieldInjector(this.injector, injectionPoint, errorsForMember)
: new SingleMethodInjector(this.injector, injectionPoint, errorsForMember);
injectors.add(injector);
} catch (ErrorsException ignoredForNow) {
// ignored for now
}
}
return ImmutableList.copyOf(injectors);
}
}

View file

@ -0,0 +1,32 @@
package com.google.inject.internal;
import com.google.inject.spi.Message;
/**
* Handles {@code Binder.addError} commands.
*
*/
final class MessageProcessor extends AbstractProcessor {
MessageProcessor(Errors errors) {
super(errors);
}
public static String getRootMessage(Throwable t) {
Throwable cause = t.getCause();
return cause == null ? t.toString() : getRootMessage(cause);
}
@Override
public Boolean visit(Message message) {
if (message.getCause() != null) {
String rootMessage = getRootMessage(message.getCause());
/*logger.log(Level.INFO,
"An exception was caught and reported. Message: " + rootMessage,
message.getCause());*/
}
errors.addMessage(message);
return true;
}
}

View file

@ -0,0 +1,19 @@
package com.google.inject.internal;
import com.google.inject.spi.ModuleAnnotatedMethodScannerBinding;
/**
* Handles {@code Binder.scanModulesForAnnotatedMethods} commands.
*/
final class ModuleAnnotatedMethodScannerProcessor extends AbstractProcessor {
ModuleAnnotatedMethodScannerProcessor(Errors errors) {
super(errors);
}
@Override
public Boolean visit(ModuleAnnotatedMethodScannerBinding command) {
injector.state.addScanner(command);
return true;
}
}

View file

@ -0,0 +1,535 @@
package com.google.inject.internal;
import com.google.common.base.Objects;
import com.google.common.collect.ImmutableMap;
import com.google.inject.ConfigurationException;
import com.google.inject.Key;
import com.google.inject.TypeLiteral;
import com.google.inject.util.Types;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.GenericDeclaration;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.reflect.WildcardType;
import java.util.Arrays;
import java.util.Map;
import java.util.NoSuchElementException;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
/**
* Static methods for working with types that we aren't publishing in the
* public {@code Types} API.
*/
public class MoreTypes {
public static final Type[] EMPTY_TYPE_ARRAY = new Type[]{};
private MoreTypes() {
}
private static final Map<TypeLiteral<?>, TypeLiteral<?>> PRIMITIVE_TO_WRAPPER
= new ImmutableMap.Builder<TypeLiteral<?>, TypeLiteral<?>>()
.put(TypeLiteral.get(boolean.class), TypeLiteral.get(Boolean.class))
.put(TypeLiteral.get(byte.class), TypeLiteral.get(Byte.class))
.put(TypeLiteral.get(short.class), TypeLiteral.get(Short.class))
.put(TypeLiteral.get(int.class), TypeLiteral.get(Integer.class))
.put(TypeLiteral.get(long.class), TypeLiteral.get(Long.class))
.put(TypeLiteral.get(float.class), TypeLiteral.get(Float.class))
.put(TypeLiteral.get(double.class), TypeLiteral.get(Double.class))
.put(TypeLiteral.get(char.class), TypeLiteral.get(Character.class))
.put(TypeLiteral.get(void.class), TypeLiteral.get(Void.class))
.build();
/**
* Returns a key that doesn't hold any references to parent classes.
* This is necessary for anonymous keys, so ensure we don't hold a ref
* to the containing module (or class) forever.
*/
public static <T> Key<T> canonicalizeKey(Key<T> key) {
// If we know this isn't a subclass, return as-is.
// Otherwise, recreate the key to avoid the subclass
if (key.getClass() == Key.class) {
return key;
} else if (key.getAnnotation() != null) {
return Key.get(key.getTypeLiteral(), key.getAnnotation());
} else if (key.getAnnotationType() != null) {
return Key.get(key.getTypeLiteral(), key.getAnnotationType());
} else {
return Key.get(key.getTypeLiteral());
}
}
/**
* Returns an type that's appropriate for use in a key.
*
* <p>If the raw type of {@code typeLiteral} is a {@code javax.inject.Provider}, this returns a
* {@code com.google.inject.Provider} with the same type parameters.
*
* <p>If the type is a primitive, the corresponding wrapper type will be returned.
*
* @throws ConfigurationException if {@code type} contains a type variable
*/
public static <T> TypeLiteral<T> canonicalizeForKey(TypeLiteral<T> typeLiteral) {
Type type = typeLiteral.getType();
if (!isFullySpecified(type)) {
Errors errors = new Errors().keyNotFullySpecified(typeLiteral);
throw new ConfigurationException(errors.getMessages());
}
if (typeLiteral.getRawType() == javax.inject.Provider.class) {
ParameterizedType parameterizedType = (ParameterizedType) type;
// the following casts are generally unsafe, but com.google.inject.Provider extends
// javax.inject.Provider and is covariant
@SuppressWarnings("unchecked")
TypeLiteral<T> guiceProviderType = (TypeLiteral<T>) TypeLiteral.get(
Types.providerOf(parameterizedType.getActualTypeArguments()[0]));
return guiceProviderType;
}
@SuppressWarnings("unchecked")
TypeLiteral<T> wrappedPrimitives = (TypeLiteral<T>) PRIMITIVE_TO_WRAPPER.get(typeLiteral);
if (wrappedPrimitives != null) {
return wrappedPrimitives;
}
// If we know this isn't a subclass, return as-is.
if (typeLiteral.getClass() == TypeLiteral.class) {
return typeLiteral;
}
// recreate the TypeLiteral to avoid anonymous TypeLiterals from holding refs to their
// surrounding classes.
@SuppressWarnings("unchecked")
TypeLiteral<T> recreated = (TypeLiteral<T>) TypeLiteral.get(typeLiteral.getType());
return recreated;
}
/**
* Returns true if {@code type} is free from type variables.
*/
private static boolean isFullySpecified(Type type) {
if (type instanceof Class) {
return true;
} else if (type instanceof CompositeType) {
return ((CompositeType) type).isFullySpecified();
} else {
return !(type instanceof TypeVariable) && ((CompositeType) canonicalize(type)).isFullySpecified();
}
}
/**
* Returns a type that is functionally equal but not necessarily equal
* according to {@link Object#equals(Object) Object.equals()}.
*/
public static Type canonicalize(Type type) {
if (type instanceof Class) {
Class<?> c = (Class<?>) type;
return c.isArray() ? new GenericArrayTypeImpl(canonicalize(c.getComponentType())) : c;
} else if (type instanceof CompositeType) {
return type;
} else if (type instanceof ParameterizedType) {
ParameterizedType p = (ParameterizedType) type;
return new ParameterizedTypeImpl(p.getOwnerType(),
p.getRawType(), p.getActualTypeArguments());
} else if (type instanceof GenericArrayType) {
GenericArrayType g = (GenericArrayType) type;
return new GenericArrayTypeImpl(g.getGenericComponentType());
} else if (type instanceof WildcardType) {
WildcardType w = (WildcardType) type;
return new WildcardTypeImpl(w.getUpperBounds(), w.getLowerBounds());
} else {
return type;
}
}
public static Class<?> getRawType(Type type) {
if (type instanceof Class<?>) {
// type is a normal class.
return (Class<?>) type;
} else if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
// I'm not exactly sure why getRawType() returns Type instead of Class.
// Neal isn't either but suspects some pathological case related
// to nested classes exists.
Type rawType = parameterizedType.getRawType();
checkArgument(rawType instanceof Class,
"Expected a Class, but <%s> is of type %s", type, type.getClass().getName());
return (Class<?>) rawType;
} else if (type instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) type).getGenericComponentType();
return Array.newInstance(getRawType(componentType), 0).getClass();
} else if (type instanceof TypeVariable) {
// we could use the variable's bounds, but that'll won't work if there are multiple.
// having a raw type that's more general than necessary is okay
return Object.class;
} else {
throw new IllegalArgumentException("Expected a Class, ParameterizedType, or "
+ "GenericArrayType, but <" + type + "> is of type " + type.getClass().getName());
}
}
/**
* Returns true if {@code a} and {@code b} are equal.
*/
public static boolean equals(Type a, Type b) {
if (a == b) {
// also handles (a == null && b == null)
return true;
} else if (a instanceof Class) {
// Class already specifies equals().
return a.equals(b);
} else if (a instanceof ParameterizedType) {
if (!(b instanceof ParameterizedType)) {
return false;
}
// TODO: save a .clone() call
ParameterizedType pa = (ParameterizedType) a;
ParameterizedType pb = (ParameterizedType) b;
return Objects.equal(pa.getOwnerType(), pb.getOwnerType())
&& pa.getRawType().equals(pb.getRawType())
&& Arrays.equals(pa.getActualTypeArguments(), pb.getActualTypeArguments());
} else if (a instanceof GenericArrayType) {
if (!(b instanceof GenericArrayType)) {
return false;
}
GenericArrayType ga = (GenericArrayType) a;
GenericArrayType gb = (GenericArrayType) b;
return equals(ga.getGenericComponentType(), gb.getGenericComponentType());
} else if (a instanceof WildcardType) {
if (!(b instanceof WildcardType)) {
return false;
}
WildcardType wa = (WildcardType) a;
WildcardType wb = (WildcardType) b;
return Arrays.equals(wa.getUpperBounds(), wb.getUpperBounds())
&& Arrays.equals(wa.getLowerBounds(), wb.getLowerBounds());
} else if (a instanceof TypeVariable) {
if (!(b instanceof TypeVariable)) {
return false;
}
TypeVariable<?> va = (TypeVariable) a;
TypeVariable<?> vb = (TypeVariable) b;
return va.getGenericDeclaration().equals(vb.getGenericDeclaration())
&& va.getName().equals(vb.getName());
} else {
// This isn't a type we support. Could be a generic array type, wildcard type, etc.
return false;
}
}
private static int hashCodeOrZero(Object o) {
return o != null ? o.hashCode() : 0;
}
public static String typeToString(Type type) {
return type instanceof Class ? ((Class) type).getName() : type.toString();
}
/**
* Returns the generic supertype for {@code type}. For example, given a class {@code IntegerSet},
* the result for when supertype is {@code Set.class} is {@code Set<Integer>} and the result
* when the supertype is {@code Collection.class} is {@code Collection<Integer>}.
*/
public static Type getGenericSupertype(Type type, Class<?> rawType, Class<?> toResolve) {
if (toResolve == rawType) {
return type;
}
// we skip searching through interfaces if unknown is an interface
if (toResolve.isInterface()) {
Class[] interfaces = rawType.getInterfaces();
for (int i = 0, length = interfaces.length; i < length; i++) {
if (interfaces[i] == toResolve) {
return rawType.getGenericInterfaces()[i];
} else if (toResolve.isAssignableFrom(interfaces[i])) {
return getGenericSupertype(rawType.getGenericInterfaces()[i], interfaces[i], toResolve);
}
}
}
// check our supertypes
if (!rawType.isInterface()) {
while (rawType != Object.class) {
Class<?> rawSupertype = rawType.getSuperclass();
if (rawSupertype == toResolve) {
return rawType.getGenericSuperclass();
} else if (toResolve.isAssignableFrom(rawSupertype)) {
return getGenericSupertype(rawType.getGenericSuperclass(), rawSupertype, toResolve);
}
rawType = rawSupertype;
}
}
// we can't resolve this further
return toResolve;
}
public static Type resolveTypeVariable(Type type, Class<?> rawType, TypeVariable unknown) {
Class<?> declaredByRaw = declaringClassOf(unknown);
// we can't reduce this further
if (declaredByRaw == null) {
return unknown;
}
Type declaredBy = getGenericSupertype(type, rawType, declaredByRaw);
if (declaredBy instanceof ParameterizedType) {
int index = indexOf(declaredByRaw.getTypeParameters(), unknown);
return ((ParameterizedType) declaredBy).getActualTypeArguments()[index];
}
return unknown;
}
private static int indexOf(Object[] array, Object toFind) {
for (int i = 0; i < array.length; i++) {
if (toFind.equals(array[i])) {
return i;
}
}
throw new NoSuchElementException();
}
/**
* Returns the declaring class of {@code typeVariable}, or {@code null} if it was not declared by
* a class.
*/
private static Class<?> declaringClassOf(TypeVariable typeVariable) {
GenericDeclaration genericDeclaration = typeVariable.getGenericDeclaration();
return genericDeclaration instanceof Class
? (Class<?>) genericDeclaration
: null;
}
private static void checkNotPrimitive(Type type, String use) {
checkArgument(!(type instanceof Class<?>) || !((Class) type).isPrimitive(),
"Primitive types are not allowed in %s: %s", use, type);
}
/**
* A type formed from other types, such as arrays, parameterized types or wildcard types
*/
private interface CompositeType {
/**
* Returns true if there are no type variables in this type.
*/
boolean isFullySpecified();
}
public static class ParameterizedTypeImpl
implements ParameterizedType, CompositeType {
private final Type ownerType;
private final Type rawType;
private final Type[] typeArguments;
public ParameterizedTypeImpl(Type ownerType, Type rawType, Type... typeArguments) {
// require an owner type if the raw type needs it
ensureOwnerType(ownerType, rawType);
this.ownerType = ownerType == null ? null : canonicalize(ownerType);
this.rawType = canonicalize(rawType);
this.typeArguments = typeArguments.clone();
for (int t = 0; t < this.typeArguments.length; t++) {
checkNotNull(this.typeArguments[t], "type parameter");
checkNotPrimitive(this.typeArguments[t], "type parameters");
this.typeArguments[t] = canonicalize(this.typeArguments[t]);
}
}
private static void ensureOwnerType(Type ownerType, Type rawType) {
if (rawType instanceof Class<?>) {
Class rawTypeAsClass = (Class) rawType;
checkArgument(ownerType != null || rawTypeAsClass.getEnclosingClass() == null,
"No owner type for enclosed %s", rawType);
checkArgument(ownerType == null || rawTypeAsClass.getEnclosingClass() != null,
"Owner type for unenclosed %s", rawType);
}
}
public Type[] getActualTypeArguments() {
return typeArguments.clone();
}
public Type getRawType() {
return rawType;
}
public Type getOwnerType() {
return ownerType;
}
public boolean isFullySpecified() {
if (ownerType != null && !MoreTypes.isFullySpecified(ownerType)) {
return false;
}
if (!MoreTypes.isFullySpecified(rawType)) {
return false;
}
for (Type type : typeArguments) {
if (!MoreTypes.isFullySpecified(type)) {
return false;
}
}
return true;
}
@Override
public boolean equals(Object other) {
return other instanceof ParameterizedType
&& MoreTypes.equals(this, (ParameterizedType) other);
}
@Override
public int hashCode() {
return Arrays.hashCode(typeArguments)
^ rawType.hashCode()
^ hashCodeOrZero(ownerType);
}
@Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder(30 * (typeArguments.length + 1));
stringBuilder.append(typeToString(rawType));
if (typeArguments.length == 0) {
return stringBuilder.toString();
}
stringBuilder.append("<").append(typeToString(typeArguments[0]));
for (int i = 1; i < typeArguments.length; i++) {
stringBuilder.append(", ").append(typeToString(typeArguments[i]));
}
return stringBuilder.append(">").toString();
}
}
public static class GenericArrayTypeImpl
implements GenericArrayType, CompositeType {
private final Type componentType;
public GenericArrayTypeImpl(Type componentType) {
this.componentType = canonicalize(componentType);
}
public Type getGenericComponentType() {
return componentType;
}
public boolean isFullySpecified() {
return MoreTypes.isFullySpecified(componentType);
}
@Override
public boolean equals(Object o) {
return o instanceof GenericArrayType
&& MoreTypes.equals(this, (GenericArrayType) o);
}
@Override
public int hashCode() {
return componentType.hashCode();
}
@Override
public String toString() {
return typeToString(componentType) + "[]";
}
}
/**
* The WildcardType interface supports multiple upper bounds and multiple
* lower bounds. We only support what the Java 6 language needs - at most one
* bound. If a lower bound is set, the upper bound must be Object.class.
*/
public static class WildcardTypeImpl
implements WildcardType, CompositeType {
private final Type upperBound;
private final Type lowerBound;
public WildcardTypeImpl(Type[] upperBounds, Type[] lowerBounds) {
checkArgument(lowerBounds.length <= 1, "Must have at most one lower bound.");
checkArgument(upperBounds.length == 1, "Must have exactly one upper bound.");
if (lowerBounds.length == 1) {
checkNotNull(lowerBounds[0], "lowerBound");
checkNotPrimitive(lowerBounds[0], "wildcard bounds");
checkArgument(upperBounds[0] == Object.class, "bounded both ways");
this.lowerBound = canonicalize(lowerBounds[0]);
this.upperBound = Object.class;
} else {
checkNotNull(upperBounds[0], "upperBound");
checkNotPrimitive(upperBounds[0], "wildcard bounds");
this.lowerBound = null;
this.upperBound = canonicalize(upperBounds[0]);
}
}
public Type[] getUpperBounds() {
return new Type[]{upperBound};
}
public Type[] getLowerBounds() {
return lowerBound != null ? new Type[]{lowerBound} : EMPTY_TYPE_ARRAY;
}
public boolean isFullySpecified() {
return MoreTypes.isFullySpecified(upperBound)
&& (lowerBound == null || MoreTypes.isFullySpecified(lowerBound));
}
@Override
public boolean equals(Object other) {
return other instanceof WildcardType
&& MoreTypes.equals(this, (WildcardType) other);
}
@Override
public int hashCode() {
// this equals Arrays.hashCode(getLowerBounds()) ^ Arrays.hashCode(getUpperBounds());
return (lowerBound != null ? 31 + lowerBound.hashCode() : 1)
^ (31 + upperBound.hashCode());
}
@Override
public String toString() {
if (lowerBound != null) {
return "? super " + typeToString(lowerBound);
} else if (upperBound == Object.class) {
return "?";
} else {
return "? extends " + typeToString(upperBound);
}
}
}
}

View file

@ -0,0 +1,32 @@
package com.google.inject.internal;
import java.lang.annotation.Annotation;
/**
* Whether a member supports null values injected.
*
* <p>Support for {@code Nullable} annotations in Guice is loose.
* Any annotation type whose simplename is "Nullable" is sufficient to indicate
* support for null values injected.
*
* <p>This allows support for JSR-305's
* <a href="http://groups.google.com/group/jsr-305/web/proposed-annotations">
* javax.annotation.meta.Nullable</a> annotation and IntelliJ IDEA's
* <a href="http://www.jetbrains.com/idea/documentation/howto.html">
* org.jetbrains.annotations.Nullable</a>.
*
*/
public class Nullability {
private Nullability() {
}
public static boolean allowsNull(Annotation[] annotations) {
for (Annotation a : annotations) {
Class<? extends Annotation> type = a.annotationType();
if ("Nullable".equals(type.getSimpleName())) {
return true;
}
}
return false;
}
}

View file

@ -0,0 +1,31 @@
package com.google.inject.internal;
import com.google.common.collect.Lists;
import com.google.inject.spi.PrivateElements;
import java.util.List;
/**
* Handles {@code Binder.newPrivateBinder()} elements.
*/
final class PrivateElementProcessor extends AbstractProcessor {
private final List<InjectorShell.Builder> injectorShellBuilders = Lists.newArrayList();
PrivateElementProcessor(Errors errors) {
super(errors);
}
@Override
public Boolean visit(PrivateElements privateElements) {
InjectorShell.Builder builder = new InjectorShell.Builder()
.parent(injector)
.privateElements(privateElements);
injectorShellBuilders.add(builder);
return true;
}
public List<InjectorShell.Builder> getInjectorShellBuilders() {
return injectorShellBuilders;
}
}

View file

@ -0,0 +1,126 @@
package com.google.inject.internal;
import com.google.common.base.MoreObjects;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.inject.Binder;
import com.google.inject.Injector;
import com.google.inject.Key;
import com.google.inject.PrivateBinder;
import com.google.inject.spi.Element;
import com.google.inject.spi.ElementVisitor;
import com.google.inject.spi.PrivateElements;
import java.util.List;
import java.util.Map;
import java.util.Set;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
public final class PrivateElementsImpl implements PrivateElements {
/*
* This class acts as both a value object and as a builder. When getElements() is called, an
* immutable collection of elements is constructed and the original mutable list is nulled out.
* Similarly, the exposed keys are made immutable on access.
*/
private final Object source;
private List<Element> elementsMutable = Lists.newArrayList();
private List<ExposureBuilder<?>> exposureBuilders = Lists.newArrayList();
/**
* lazily instantiated
*/
private ImmutableList<Element> elements;
/**
* lazily instantiated
*/
private ImmutableMap<Key<?>, Object> exposedKeysToSources;
private Injector injector;
public PrivateElementsImpl(Object source) {
this.source = checkNotNull(source, "source");
}
public Object getSource() {
return source;
}
public List<Element> getElements() {
if (elements == null) {
elements = ImmutableList.copyOf(elementsMutable);
elementsMutable = null;
}
return elements;
}
public Injector getInjector() {
return injector;
}
public void initInjector(Injector injector) {
checkState(this.injector == null, "injector already initialized");
this.injector = checkNotNull(injector, "injector");
}
public Set<Key<?>> getExposedKeys() {
if (exposedKeysToSources == null) {
Map<Key<?>, Object> exposedKeysToSourcesMutable = Maps.newLinkedHashMap();
for (ExposureBuilder<?> exposureBuilder : exposureBuilders) {
exposedKeysToSourcesMutable.put(exposureBuilder.getKey(), exposureBuilder.getSource());
}
exposedKeysToSources = ImmutableMap.copyOf(exposedKeysToSourcesMutable);
exposureBuilders = null;
}
return exposedKeysToSources.keySet();
}
public <T> T acceptVisitor(ElementVisitor<T> visitor) {
return visitor.visit(this);
}
public List<Element> getElementsMutable() {
return elementsMutable;
}
public void addExposureBuilder(ExposureBuilder<?> exposureBuilder) {
exposureBuilders.add(exposureBuilder);
}
public void applyTo(Binder binder) {
PrivateBinder privateBinder = binder.withSource(source).newPrivateBinder();
for (Element element : getElements()) {
element.applyTo(privateBinder);
}
getExposedKeys(); // ensure exposedKeysToSources is populated
for (Map.Entry<Key<?>, Object> entry : exposedKeysToSources.entrySet()) {
privateBinder.withSource(entry.getValue()).expose(entry.getKey());
}
}
public Object getExposedSource(Key<?> key) {
getExposedKeys(); // ensure exposedKeysToSources is populated
Object source = exposedKeysToSources.get(key);
checkArgument(source != null, "%s not exposed by %s.", key, this);
return source;
}
@Override
public String toString() {
return MoreObjects.toStringHelper(PrivateElements.class)
.add("exposedKeys", getExposedKeys())
.add("source", getSource())
.toString();
}
}

Some files were not shown because too many files have changed in this diff Show more