Search in sources :

Example 36 with ProvisionException

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());
}
Also used : ProvisionException(com.google.inject.ProvisionException) Injector(com.google.inject.Injector) OutOfScopeException(com.google.inject.OutOfScopeException) Key(com.google.inject.Key)

Example 37 with ProvisionException

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) + "]");
    }
}
Also used : Named(com.google.inject.name.Named) ProvisionException(com.google.inject.ProvisionException) Injector(com.google.inject.Injector) Provides(com.google.inject.Provides) AbstractModule(com.google.inject.AbstractModule)

Example 38 with ProvisionException

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);
        }
    };
}
Also used : Message(com.google.inject.spi.Message) Formatter(java.util.Formatter) ProvisionException(com.google.inject.ProvisionException) Provider(com.google.inject.Provider) ListMultimap(com.google.common.collect.ListMultimap) Key(com.google.inject.Key)

Example 39 with ProvisionException

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");
    }
}
Also used : ProvisionException(com.google.inject.ProvisionException) Injector(com.google.inject.Injector) Singleton(com.google.inject.Singleton) Provides(com.google.inject.Provides) AbstractModule(com.google.inject.AbstractModule)

Example 40 with ProvisionException

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();
        }
    };
}
Also used : ProvisionException(com.google.inject.ProvisionException) Dependency(com.google.inject.spi.Dependency) SourceProvider(com.google.inject.internal.util.SourceProvider) Provider(com.google.inject.Provider)

Aggregations

ProvisionException (com.google.inject.ProvisionException)57 Injector (com.google.inject.Injector)22 AbstractModule (com.google.inject.AbstractModule)20 Module (com.google.inject.Module)11 Provider (com.google.inject.Provider)9 OutOfScopeException (com.google.inject.OutOfScopeException)6 TypeLiteral (com.google.inject.TypeLiteral)6 Key (com.google.inject.Key)5 Message (com.google.inject.spi.Message)5 ImmutableList (com.google.common.collect.ImmutableList)4 ReviewDb (com.google.gerrit.reviewdb.server.ReviewDb)4 OrmException (com.google.gwtorm.server.OrmException)4 IOException (java.io.IOException)4 ArrayList (java.util.ArrayList)4 List (java.util.List)4 Provides (com.google.inject.Provides)3 Dependency (com.google.inject.spi.Dependency)3 InvocationTargetException (java.lang.reflect.InvocationTargetException)3 Method (java.lang.reflect.Method)3 Path (java.nio.file.Path)3