use of com.google.inject.ProvisionException in project guice by google.
the class ScopeRequestIntegrationTest method testNullReplacement.
public final void testNullReplacement() throws Exception {
Injector injector = Guice.createInjector(new ServletModule() {
@Override
protected void configureServlets() {
bindConstant().annotatedWith(Names.named(SomeObject.INVALID)).to(SHOULDNEVERBESEEN);
bind(SomeObject.class).in(RequestScoped.class);
}
});
Callable<SomeObject> callable = injector.getInstance(Caller.class);
try {
assertNotNull(callable.call());
fail();
} catch (ProvisionException pe) {
assertTrue(pe.getCause() instanceof OutOfScopeException);
}
// Validate that an actual null entry in the map results in a null injected object.
Map<Key<?>, Object> map = Maps.newHashMap();
map.put(Key.get(SomeObject.class), null);
callable = ServletScopes.scopeRequest(injector.getInstance(Caller.class), map);
assertNull(callable.call());
}
use of com.google.inject.ProvisionException in project guice by google.
the class ServletTest method testScopeExceptions.
public void testScopeExceptions() throws Exception {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
install(new ServletModule());
}
@Provides
@RequestScoped
String provideString() {
return "foo";
}
@Provides
@SessionScoped
Integer provideInteger() {
return 1;
}
@Provides
@RequestScoped
@Named("foo")
String provideNamedString() {
return "foo";
}
});
try {
injector.getInstance(String.class);
fail();
} catch (ProvisionException oose) {
assertContains(oose.getMessage(), "Cannot access scoped [java.lang.String].");
}
try {
injector.getInstance(Integer.class);
fail();
} catch (ProvisionException oose) {
assertContains(oose.getMessage(), "Cannot access scoped [java.lang.Integer].");
}
Key<?> key = Key.get(String.class, Names.named("foo"));
try {
injector.getInstance(key);
fail();
} catch (ProvisionException oose) {
assertContains(oose.getMessage(), "Cannot access scoped [" + Errors.convert(key) + "]");
}
}
use of com.google.inject.ProvisionException in project guice by google.
the class SingletonScope method scope.
/**
* Provides singleton scope with the following properties: - creates no more than one instance per
* Key as a creator is used no more than once, - result is cached and returned quickly on
* subsequent calls, - exception in a creator is not treated as instance creation and is not
* cached, - creates singletons in parallel whenever possible, - waits for dependent singletons to
* be created even across threads and when dependencies are shared as long as no circular
* dependencies are detected, - returns circular proxy only when circular dependencies are
* detected, - aside from that, blocking synchronization is only used for proxy creation and
* initialization,
*
* @see CycleDetectingLockFactory
*/
@Override
public <T> Provider<T> scope(final Key<T> key, final Provider<T> creator) {
/**
* Locking strategy: - volatile instance: double-checked locking for quick exit when scope is
* initialized, - constructionContext: manipulations with proxies list or instance
* initialization - creationLock: singleton instance creation, -- allows to guarantee only one
* instance per singleton, -- special type of a lock, that prevents potential deadlocks, --
* guards constructionContext for all operations except proxy creation
*/
return new Provider<T>() {
/**
* The lazily initialized singleton instance. Once set, this will either have type T or will
* be equal to NULL. Would never be reset to null.
*/
volatile Object instance;
/**
* Circular proxies are used when potential deadlocks are detected. Guarded by itself.
* ConstructionContext is not thread-safe, so each call should be synchronized.
*/
final ConstructionContext<T> constructionContext = new ConstructionContext<T>();
/** For each binding there is a separate lock that we hold during object creation. */
final CycleDetectingLock<Key<?>> creationLock = cycleDetectingLockFactory.create(key);
/**
* The singleton provider needs a reference back to the injector, in order to get ahold of
* InternalContext during instantiation.
*/
final InjectorImpl /* @Nullable */
injector;
{
// If we are getting called by Scoping
if (creator instanceof ProviderToInternalFactoryAdapter) {
injector = ((ProviderToInternalFactoryAdapter) creator).getInjector();
} else {
injector = null;
}
}
@SuppressWarnings("DoubleCheckedLocking")
@Override
public T get() {
// cache volatile variable for the usual case of already initialized object
final Object initialInstance = instance;
if (initialInstance == null) {
// instance is not initialized yet
// first, store the current InternalContext in a map, so that if there is a circular
// dependency error, we can use the InternalContext objects to create a complete
// error message.
// Handle injector being null, which can happen when users call Scoping.scope themselves
final InternalContext context = injector == null ? null : injector.getLocalContext();
// acquire lock for current binding to initialize an instance
final ListMultimap<Thread, Key<?>> locksCycle = creationLock.lockOrDetectPotentialLocksCycle();
if (locksCycle.isEmpty()) {
// this thread now owns creation of an instance
try {
// intentionally reread volatile variable to prevent double initialization
if (instance == null) {
// creator throwing an exception can cause circular proxies created in
// different thread to never be resolved, just a warning
T provided = creator.get();
Object providedNotNull = provided == null ? NULL : provided;
// scope called recursively can initialize instance as a side effect
if (instance == null) {
// detection within the same thread; they are not real instances to cache
if (Scopes.isCircularProxy(provided)) {
return provided;
}
synchronized (constructionContext) {
// guarantee thread-safety for instance and proxies initialization
instance = providedNotNull;
constructionContext.setProxyDelegates(provided);
}
} else {
// safety assert in case instance was initialized
Preconditions.checkState(instance == providedNotNull, "Singleton is called recursively returning different results");
}
}
} catch (RuntimeException e) {
// this helps to prevent potential memory leaks in circular proxies list
synchronized (constructionContext) {
constructionContext.finishConstruction();
}
throw e;
} finally {
// always release our creation lock, even on failures
creationLock.unlock();
}
} else {
if (context == null) {
throw new ProvisionException(ImmutableList.of(createCycleDependenciesMessage(locksCycle, null)));
}
// potential deadlock detected, creation lock is not taken by this thread
synchronized (constructionContext) {
// guarantee thread-safety for instance and proxies initialization
if (instance == null) {
// creating a proxy to satisfy circular dependency across several threads
Dependency<?> dependency = Preconditions.checkNotNull(context.getDependency(), "internalContext.getDependency()");
Class<?> rawType = dependency.getKey().getTypeLiteral().getRawType();
try {
@SuppressWarnings("unchecked") T proxy = (T) constructionContext.createProxy(new Errors(), context.getInjectorOptions(), rawType);
return proxy;
} catch (ErrorsException e) {
// best effort to create a rich error message
Message proxyCreationError = Iterables.getOnlyElement(e.getErrors().getMessages());
Message cycleDependenciesMessage = createCycleDependenciesMessage(locksCycle, proxyCreationError);
// adding stack trace generated by us in addition to a standard one
throw new ProvisionException(ImmutableList.of(cycleDependenciesMessage, proxyCreationError));
}
}
}
}
// at this point we're sure that singleton was initialized,
// reread volatile variable to catch all corner cases
// caching volatile variable to minimize number of reads performed
final Object initializedInstance = instance;
Preconditions.checkState(initializedInstance != null, "Internal error: Singleton is not initialized contrary to our expectations");
@SuppressWarnings("unchecked") T initializedTypedInstance = (T) initializedInstance;
return initializedInstance == NULL ? null : initializedTypedInstance;
} else {
// singleton is already initialized and local cache can be used
@SuppressWarnings("unchecked") T typedInitialIntance = (T) initialInstance;
return initialInstance == NULL ? null : typedInitialIntance;
}
}
/**
* Helper method to create beautiful and rich error descriptions. Best effort and slow. Tries
* its best to provide dependency information from injectors currently available in a global
* internal context.
*
* <p>The main thing being done is creating a list of Dependencies involved into lock cycle
* across all the threads involved. This is a structure we're creating:
*
* <pre>
* { Current Thread, C.class, B.class, Other Thread, B.class, C.class, Current Thread }
* To be inserted in the beginning by Guice: { A.class, B.class, C.class }
* </pre>
*
* When we're calling Guice to create A and it fails in the deadlock while trying to create C,
* which is being created by another thread, which waits for B. List would be reversed before
* printing it to the end user.
*/
private Message createCycleDependenciesMessage(ListMultimap<Thread, Key<?>> locksCycle, /* @Nullable */
Message proxyCreationError) {
// this is the main thing that we'll show in an error message,
// current thread is populate by Guice
StringBuilder sb = new StringBuilder();
Formatter fmt = new Formatter(sb);
fmt.format("Encountered circular dependency spanning several threads.");
if (proxyCreationError != null) {
fmt.format(" %s", proxyCreationError.getMessage());
}
fmt.format("%n");
for (Thread lockedThread : locksCycle.keySet()) {
List<Key<?>> lockedKeys = locksCycle.get(lockedThread);
fmt.format("%s is holding locks the following singletons in the cycle:%n", lockedThread);
for (Key<?> lockedKey : lockedKeys) {
fmt.format("%s%n", Errors.convert(lockedKey));
}
for (StackTraceElement traceElement : lockedThread.getStackTrace()) {
fmt.format("\tat %s%n", traceElement);
}
}
fmt.close();
return new Message(Thread.currentThread(), sb.toString());
}
@Override
public String toString() {
return String.format("%s[%s]", creator, Scopes.SINGLETON);
}
};
}
use of com.google.inject.ProvisionException in project guice by google.
the class ProviderMethodsTest method testScopedProviderMethodThrowsException.
public void testScopedProviderMethodThrowsException() {
Injector injector = Guice.createInjector(new AbstractModule() {
@Override
protected void configure() {
}
@Provides
@Singleton
int provideInt() {
throw new RuntimeException("boom");
}
});
Provider<Integer> intProvider = injector.getProvider(Integer.class);
try {
intProvider.get();
fail();
} catch (ProvisionException pe) {
// by default assertContains asserts that the last item doesn't repeat... which is the main
// thing we are testing for
assertContains(pe.getMessage(), "java.lang.RuntimeException: boom", "provideInt");
}
}
use of com.google.inject.ProvisionException in project roboguice by roboguice.
the class InjectorImpl method getProviderOrThrow.
<T> Provider<T> getProviderOrThrow(final Key<T> key, Errors errors) throws ErrorsException {
final BindingImpl<? extends T> binding = getBindingOrThrow(key, errors, JitLimitation.NO_JIT);
final Dependency<T> dependency = Dependency.get(key);
return new Provider<T>() {
public T get() {
final Errors errors = new Errors(dependency);
try {
T t = callInContext(new ContextualCallable<T>() {
public T call(InternalContext context) throws ErrorsException {
Dependency previous = context.pushDependency(dependency, binding.getSource());
try {
return binding.getInternalFactory().get(errors, context, dependency, false);
} finally {
context.popStateAndSetDependency(previous);
}
}
});
errors.throwIfNewErrors(0);
return t;
} catch (ErrorsException e) {
throw new ProvisionException(errors.merge(e.getErrors()).getMessages());
}
}
@Override
public String toString() {
return binding.getInternalFactory().toString();
}
};
}
Aggregations