All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.google.inject.internal.MembersInjectorImpl Maven / Gradle / Ivy

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 implements MembersInjector {

    private final TypeLiteral typeLiteral;

    private final InjectorImpl injector;

    private final ImmutableList memberInjectors;

    private final ImmutableList> userMembersInjectors;

    private final ImmutableList> injectionListeners;

    MembersInjectorImpl(InjectorImpl injector,
                        TypeLiteral typeLiteral,
                        EncounterImpl encounter,
                        ImmutableList memberInjectors) {
        this.injector = injector;
        this.typeLiteral = typeLiteral;
        this.memberInjectors = memberInjectors.isEmpty() ? null : memberInjectors;
        this.userMembersInjectors =
                encounter.getMembersInjectors().isEmpty() ? null : encounter.getMembersInjectors().asList();
        this.injectionListeners =
                encounter.getInjectionListeners().isEmpty()
                        ? null
                        : encounter.getInjectionListeners().asList();
    }

    public ImmutableList getMemberInjectors() {
        return  memberInjectors == null ? ImmutableList.of() : memberInjectors;
    }

    public void injectMembers(T instance) {
        TypeLiteral localTypeLiteral = typeLiteral;
        try {
            injectAndNotify(instance, null, null, localTypeLiteral, false);
        } catch (InternalProvisionException ipe) {
            throw ipe.addSource(localTypeLiteral).toProvisionException();
        }
    }

    void injectAndNotify(final T instance,
                         final Key key, // possibly null!
                         final ProvisionListenerStackCallback provisionCallback, // possibly null!
                         final Object source,
                         final boolean toolableOnly) throws InternalProvisionException {
        if (instance == null) {
            return;
        }
        final InternalContext context = injector.enterContext();
        context.pushState(key, source);
        try {
            if (provisionCallback != null && provisionCallback.hasListeners()) {
                provisionCallback.provision(context, () -> {
                            injectMembers(instance, context, toolableOnly);
                            return instance;
                        });
            } else {
                injectMembers(instance, context, toolableOnly);
            }
        } finally {
            context.popState();
            context.close();
        }

        // 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);
        }
    }

    void notifyListeners(T instance) throws InternalProvisionException {
        ImmutableList> localInjectionListeners = injectionListeners;
        if (localInjectionListeners == null) {
            // no listeners
            return;
        }
        // optimization: use manual for/each to save allocating an iterator here
        for (int i = 0; i < localInjectionListeners.size(); i++) {
            InjectionListener injectionListener = localInjectionListeners.get(i);
            try {
                injectionListener.afterInjection(instance);
            } catch (RuntimeException e) {
                throw InternalProvisionException.errorNotifyingInjectionListener(
                        injectionListener, typeLiteral, e);
            }
        }
    }

    void injectMembers(T t,  InternalContext context, boolean toolableOnly)
            throws InternalProvisionException {
        ImmutableList localMembersInjectors = memberInjectors;
        if (localMembersInjectors != null) {
            // optimization: use manual for/each to save allocating an iterator here
            for (int i = 0, size = localMembersInjectors.size(); i < size; i++) {
                SingleMemberInjector injector = localMembersInjectors.get(i);
                if (!toolableOnly || injector.getInjectionPoint().isToolable()) {
                    injector.inject(context, t);
                }
            }
        }

        // TODO: There's no way to know if a user's MembersInjector wants toolable injections.
        if (!toolableOnly) {
            ImmutableList> localUsersMembersInjectors = userMembersInjectors;
            if (localUsersMembersInjectors != null) {
                // optimization: use manual for/each to save allocating an iterator here
                for (int i = 0; i < localUsersMembersInjectors.size(); i++) {
                    MembersInjector userMembersInjector = localUsersMembersInjectors.get(i);
                    try {
                        userMembersInjector.injectMembers(t);
                    } catch (RuntimeException e) {
                        throw InternalProvisionException.errorInUserInjector(
                                userMembersInjector, typeLiteral, e);
                    }
                }
            }
        }
    }

    @Override
    public String toString() {
        return "MembersInjector<" + typeLiteral + ">";
    }

    public ImmutableSet getInjectionPoints() {
        ImmutableList localMemberInjectors = memberInjectors;
        if (localMemberInjectors != null) {
            ImmutableSet.Builder builder = ImmutableSet.builder();
            for (SingleMemberInjector memberInjector : localMemberInjectors) {
                builder.add(memberInjector.getInjectionPoint());
            }
            return builder.build();
        }
        return ImmutableSet.of();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy