Search in sources :

Example 86 with Provider

use of com.google.inject.Provider in project guice by google.

the class BoundFieldModuleTest method testRawProviderCanBindToIncorrectType.

public void testRawProviderCanBindToIncorrectType() {
    final Integer testValue = 1024;
    Object instance = new Object() {

        @Bind(to = String.class)
        private Provider anIntProvider = new Provider() {

            @Override
            public Object get() {
                return testValue;
            }
        };
    };
    BoundFieldModule module = BoundFieldModule.of(instance);
    Injector injector = Guice.createInjector(module);
    assertEquals(testValue, injector.getInstance(String.class));
}
Also used : Injector(com.google.inject.Injector) Provider(com.google.inject.Provider)

Example 87 with Provider

use of com.google.inject.Provider in project guice by google.

the class BoundFieldModuleTest method testExplicitlyBoundRawProviderCanBeBound.

public void testExplicitlyBoundRawProviderCanBeBound() {
    final Integer testValue = 1024;
    Object instance = new Object() {

        @Bind(to = Integer.class)
        private Provider anIntProvider = new Provider() {

            @Override
            public Object get() {
                return testValue;
            }
        };
    };
    BoundFieldModule module = BoundFieldModule.of(instance);
    Injector injector = Guice.createInjector(module);
    assertEquals(testValue, injector.getInstance(Integer.class));
}
Also used : Injector(com.google.inject.Injector) Provider(com.google.inject.Provider)

Example 88 with Provider

use of com.google.inject.Provider in project guice by google.

the class BoundFieldModuleTest method testBindingProviderWithProviderSubclassValue.

public void testBindingProviderWithProviderSubclassValue() {
    final Integer testValue = 1024;
    Object instance = new Object() {

        @Bind
        private Provider<Integer> anIntProvider = new IntegerProvider(testValue);
    };
    BoundFieldModule module = BoundFieldModule.of(instance);
    Injector injector = Guice.createInjector(module);
    assertEquals(testValue, injector.getInstance(Integer.class));
}
Also used : Injector(com.google.inject.Injector) Provider(com.google.inject.Provider)

Example 89 with Provider

use of com.google.inject.Provider in project guice by google.

the class BoundFieldModuleTest method testRawProviderCannotBeBound.

public void testRawProviderCannotBeBound() {
    final Integer testValue = 1024;
    Object instance = new Object() {

        @Bind
        private Provider anIntProvider = new Provider() {

            @Override
            public Object get() {
                return testValue;
            }
        };
    };
    BoundFieldModule module = BoundFieldModule.of(instance);
    try {
        Guice.createInjector(module);
        fail();
    } catch (CreationException e) {
        assertContains(e.getMessage(), "Non parameterized Provider fields must have an " + "explicit binding class via @Bind(to = Foo.class)");
    }
}
Also used : CreationException(com.google.inject.CreationException) Provider(com.google.inject.Provider)

Example 90 with Provider

use of com.google.inject.Provider 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)

Aggregations

Provider (com.google.inject.Provider)133 Injector (com.google.inject.Injector)72 AbstractModule (com.google.inject.AbstractModule)63 Module (com.google.inject.Module)44 Key (com.google.inject.Key)17 TypeLiteral (com.google.inject.TypeLiteral)10 ArrayList (java.util.ArrayList)10 ProvisionException (com.google.inject.ProvisionException)9 Dependency (com.google.inject.spi.Dependency)9 Map (java.util.Map)8 Before (org.junit.Before)7 CurrentUser (com.google.gerrit.server.CurrentUser)6 RequestContext (com.google.gerrit.server.util.RequestContext)6 ThreadLocalRequestContext (com.google.gerrit.server.util.ThreadLocalRequestContext)6 InMemoryModule (com.google.gerrit.testutil.InMemoryModule)6 PrivateModule (com.google.inject.PrivateModule)6 Scope (com.google.inject.Scope)6 List (java.util.List)6 AtomicReference (java.util.concurrent.atomic.AtomicReference)6 Annotation (java.lang.annotation.Annotation)5