Search in sources :

Example 71 with Key

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

the class ThrowingProviderTest method testDependencies_Provides.

public void testDependencies_Provides() {
    providesInjector = Guice.createInjector(new AbstractModule() {

        @Override
        protected void configure() {
            bind(String.class).toInstance("Foo");
            bind(Integer.class).toInstance(5);
            bind(Double.class).toInstance(5d);
            bind(Long.class).toInstance(5L);
            install(ThrowingProviderBinder.forModule(this));
        }

        @SuppressWarnings("unused")
        @CheckedProvides(RemoteProvider.class)
        String foo(String s, Integer i, Double d, Long l) {
            return null;
        }
    });
    HasDependencies hasDependencies = (HasDependencies) providesInjector.getBinding(Key.get(remoteProviderOfString));
    // RemoteProvider<String> is dependent on the provider method..
    hasDependencies = (HasDependencies) providesInjector.getBinding(Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey());
    // And the provider method has our real dependencies..
    hasDependencies = (HasDependencies) providesInjector.getBinding(Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey());
    Set<Key<?>> dependencyKeys = ImmutableSet.copyOf(Iterables.transform(hasDependencies.getDependencies(), new Function<Dependency<?>, Key<?>>() {

        @Override
        public Key<?> apply(Dependency<?> from) {
            return from.getKey();
        }
    }));
    assertEquals(ImmutableSet.<Key<?>>of(Key.get(String.class), Key.get(Integer.class), Key.get(Long.class), Key.get(Double.class)), dependencyKeys);
}
Also used : Function(com.google.common.base.Function) Dependency(com.google.inject.spi.Dependency) HasDependencies(com.google.inject.spi.HasDependencies) Key(com.google.inject.Key) AbstractModule(com.google.inject.AbstractModule)

Example 72 with Key

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

the class Java8LanguageFeatureBindingTest method testBinding_lambdaToInterface.

// Some of these tests are kind of weird.
// See https://github.com/google/guice/issues/757 for more on why they exist.
public void testBinding_lambdaToInterface() {
    Injector injector = Guice.createInjector(new AbstractModule() {

        @Override
        protected void configure() {
            bind(new TypeLiteral<Predicate<Object>>() {
            }).toInstance(o -> o != null);
        }
    });
    Predicate<Object> predicate = injector.getInstance(new Key<Predicate<Object>>() {
    });
    assertTrue(predicate.test(new Object()));
    assertFalse(predicate.test(null));
}
Also used : Predicate(java.util.function.Predicate) Inject(com.google.inject.Inject) Key(com.google.inject.Key) Callable(java.util.concurrent.Callable) UUID(java.util.UUID) Injector(com.google.inject.Injector) Provider(com.google.inject.Provider) CreationException(com.google.inject.CreationException) Provides(com.google.inject.Provides) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Guice(com.google.inject.Guice) ProvisionException(com.google.inject.ProvisionException) TestCase(junit.framework.TestCase) TypeLiteral(com.google.inject.TypeLiteral) Collections(java.util.Collections) AbstractModule(com.google.inject.AbstractModule) Injector(com.google.inject.Injector) AbstractModule(com.google.inject.AbstractModule) Predicate(java.util.function.Predicate)

Example 73 with Key

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

the class ThrowingProviderTest method testDependencies_Bind.

public void testDependencies_Bind() {
    bindInjector = Guice.createInjector(new AbstractModule() {

        @Override
        protected void configure() {
            bind(String.class).toInstance("Foo");
            bind(Integer.class).toInstance(5);
            bind(Double.class).toInstance(5d);
            bind(Long.class).toInstance(5L);
            ThrowingProviderBinder.create(binder()).bind(RemoteProvider.class, String.class).to(DependentRemoteProvider.class);
        }
    });
    HasDependencies hasDependencies = (HasDependencies) bindInjector.getBinding(Key.get(remoteProviderOfString));
    hasDependencies = (HasDependencies) bindInjector.getBinding(Iterables.getOnlyElement(hasDependencies.getDependencies()).getKey());
    // Make sure that that is dependent on DependentRemoteProvider.
    assertEquals(Dependency.get(Key.get(DependentRemoteProvider.class)), Iterables.getOnlyElement(hasDependencies.getDependencies()));
    // And make sure DependentRemoteProvider has the proper dependencies.
    hasDependencies = (HasDependencies) bindInjector.getBinding(DependentRemoteProvider.class);
    Set<Key<?>> dependencyKeys = ImmutableSet.copyOf(Iterables.transform(hasDependencies.getDependencies(), new Function<Dependency<?>, Key<?>>() {

        @Override
        public Key<?> apply(Dependency<?> from) {
            return from.getKey();
        }
    }));
    assertEquals(ImmutableSet.<Key<?>>of(Key.get(String.class), Key.get(Integer.class), Key.get(Long.class), Key.get(Double.class)), dependencyKeys);
}
Also used : Function(com.google.common.base.Function) Dependency(com.google.inject.spi.Dependency) HasDependencies(com.google.inject.spi.HasDependencies) Key(com.google.inject.Key) AbstractModule(com.google.inject.AbstractModule)

Example 74 with Key

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

the class BoundFieldModuleTest method testBindingWithGenerics.

public void testBindingWithGenerics() {
    final List<Integer> testIntList = Arrays.asList(new Integer[] { 1, 2, 3 });
    final List<Boolean> testBoolList = Arrays.asList(new Boolean[] { true, true, false });
    Object instance = new Object() {

        @Bind
        private List<Integer> anIntList = testIntList;

        @Bind
        private List<Boolean> aBoolList = testBoolList;
    };
    BoundFieldModule module = BoundFieldModule.of(instance);
    Injector injector = Guice.createInjector(module);
    assertEquals(testIntList, injector.getInstance(new Key<List<Integer>>() {
    }));
    assertEquals(testBoolList, injector.getInstance(new Key<List<Boolean>>() {
    }));
}
Also used : Injector(com.google.inject.Injector) List(java.util.List) Key(com.google.inject.Key)

Example 75 with Key

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

Key (com.google.inject.Key)106 AbstractModule (com.google.inject.AbstractModule)55 Injector (com.google.inject.Injector)52 Binding (com.google.inject.Binding)36 Module (com.google.inject.Module)20 Provider (com.google.inject.Provider)18 Element (com.google.inject.spi.Element)16 Map (java.util.Map)16 HasDependencies (com.google.inject.spi.HasDependencies)14 InstanceBinding (com.google.inject.spi.InstanceBinding)13 List (java.util.List)13 TypeLiteral (com.google.inject.TypeLiteral)12 LinkedKeyBinding (com.google.inject.spi.LinkedKeyBinding)10 ProviderInstanceBinding (com.google.inject.spi.ProviderInstanceBinding)9 PrivateModule (com.google.inject.PrivateModule)8 DefaultBindingTargetVisitor (com.google.inject.spi.DefaultBindingTargetVisitor)8 Dependency (com.google.inject.spi.Dependency)8 ProviderKeyBinding (com.google.inject.spi.ProviderKeyBinding)8 ImmutableList (com.google.common.collect.ImmutableList)7 InjectionPoint (com.google.inject.spi.InjectionPoint)7